We have a Python dictionary sitting on a server, and we want to write this dictionary out to a page as a JSON object, ready for client-side Javascript codes. Not all Flask template functions work as I thought they would. I'm documenting my experimentations in this post.
Let's go straight to the short discussion first, hopefully it's enough, then readers should not have to go the next section, where I'm demonstrating with codes built upon existing code from some other posts.
Converting a Python dictionary to JSON is fairly straightforward:
import simplejson as json
data = { ... }
print( json.dumps(data) )
The returned value of json.dumps( obj: dict ) is a valid JSON object, which client-side JavaScript can use immediately. I've tried the following to get this returned value to the page:
...
def json_dumps( obj: dict ):
return json.dumps( obj )
@app.context_processor
def json_dumps_context_processor():
def __json_dumps_context_processor( obj: dict ):
return json_dumps( obj )
return dict( json_dumps_context_processor=__json_dumps_context_processor )
@app.template_global()
def json_dumps_template_global( obj: dict ):
return json_dumps( obj )
@app.template_filter()
def json_dumps_decorator_filter( obj: dict ):
return json_dumps( obj )
"""
This registration gets executed automatically by the import
statement, thereby enabling json_dumps_jinja_filter available
to template rendering function.
"""
app.jinja_env.filters[ 'json_dumps_jinja_filter' ] = json_dumps
Please note: four ( 4 ) different methods, but they all call to the same function to do the work.
The codes to render a template:
data = { ... }
return render_template( 'some_template_file.html', json_obj=data )
Inside some_template_file.html, we call the above four ( 4 ) template functions as illustrated:
<script>
var jsonObj1 = {{ json_dumps_context_processor(json_obj) }};
var jsonObj2 = {{ json_dumps_template_global(json_obj) }};
var jsonObj3 = {{ json_obj|json_dumps_decorator_filter|safe }};
var jsonObj4 = {{ json_obj|json_dumps_jinja_filter|safe }};
</script>
The final HTML will cause run-time errors due to the first two ( 2 ) lines: double quotation marks ( " ) are output as escape code ".
The @app.template_filter() and app.jinja_env.filters work as expected. Personally, I like @app.template_filter() much better: I'm using it for this task.
I did not investigate why @app.context_processor and @app.template_global() do not work in this case, ( because there's already a ready-made solution ).
For @app.template_global(), please see https://flask.palletsprojects.com/en/2.2.x/api/ -- we have to search for template_global. For the others, please see https://flask.palletsprojects.com/en/2.2.x/templating/.
The demo codes for this post can be downloaded via:
git clone -b v1.0.5 https://github.com/behai-nguyen/app-demo.git
Please note, the tag is v1.0.5. Please ignore all Docker related files.
✿✿✿
I've previously discussed @app.context_processor in Python: pytest and Flask template context processor functions. The demo codes for this post will build upon the existing codes in the just mentioned post.
The diagram below shows the project layout when completed. Please note ★ indicates new files, and ☆ indicates files which have been modified:
D:\app_demo\
|
|-- .env
|-- app.py
|-- setup.py ☆
|-- pytest.ini
|
|-- src\
| |
| |-- app_demo\
| |
| |-- __init__.py
| |-- config.py
| |-- urls.py ☆
| |
| |-- controllers\
| | |
| | |-- __init__.py ☆
| | |-- echo.py
| | |-- json_dumps.py ★
| |
| |-- utils\
| | |
| | |-- __init__.py
| | |-- context_processor.py ☆
| | |-- functions.py
| |
| |-- templates\
| | |
| | |-- base_template.html
| | |-- echo\
| | | |
| | | |--echo.html
| | |
| | |-- json\
| | | |
| | | |--json_dumps.html ★
|
|-- tests
| ...
|
|-- venv\
The codes are very simple, most are one liner. We briefly look at the changes below.
❶ setup.py -- include new package simplejson. To install, run:
(venv) D:\app_demo>venv\Scripts\pip.exe install -e .
(venv) behai@omphalos-nas-01:/volume1/web/app_demo$ sudo venv/bin/pip install -e .
❷ src/app_demo/utils/context_processor.py -- added new template processing functions discussed above:
def json_dumps_context_processor():
def json_dumps_template_global( obj: dict ):
def json_dumps_decorator_filter( obj: dict ):
app.jinja_env.filters[ 'json_dumps_jinja_filter' ] = json_dumps
❸ src/app_demo/controllers/__init__.py -- added new Blueprint: json_blueprint.
❹ src/app_demo/controllers/json_dumps.py -- controller code which serves static response for new route /json. The hard-coded dictionary is real data from a project I'm currently working on.
❺ src/app_demo/templates/json/json_dumps.html -- demo template for new route /json. We've discussed this template in the first section.
The new route http://localhost:5000/json -- serves the final content of this template. This is a static content. We have to do browsers' view page source to see the actual output.
❻ src/app_demo/urls.py -- register the new Blueprint: json_blueprint, and new route /json discussed above.
To recap, the codes for this post can be downloaded using:
git clone -b v1.0.5 https://github.com/behai-nguyen/app-demo.git
The tag is v1.0.5. Please ignore all Docker related files.
I hope you find this post useful... Thank you for reading and stay safe.
Top comments (0)