Templating and JSON
Flask provides integrated support for rendering HTML templates using the Jinja2 engine and handling JSON data serialization. These features are designed to be extensible, allowing for custom template loaders, context variables, and specialized JSON serialization logic.
HTML Templating with Jinja2
Flask uses Jinja2 as its default templating engine. The integration is primarily handled through the flask.templating module and the Environment class, which extends the standard Jinja2 environment with Flask-specific features.
Rendering Templates
The primary functions for rendering templates are render_template and render_template_string, found in src/flask/templating.py.
render_template(template_name_or_list, **context): Renders a template file by name. It looks for the file in the application's template folder or within registered blueprints.render_template_string(source, **context): Renders a template from a raw string.
Example from examples/tutorial/flaskr/blog.py:
@bp.route("/")
def index():
db = get_db()
posts = db.execute(
"SELECT p.id, title, body, created, author_id, username"
" FROM post p JOIN user u ON p.author_id = u.id"
" ORDER BY created DESC"
).fetchall()
return render_template("blog/index.html", posts=posts)
Template Discovery and Blueprints
Flask uses a custom loader called DispatchingJinjaLoader (in src/flask/templating.py) to locate templates. This loader searches for templates in the following order:
- The application's own template folder.
- The template folders of all registered blueprints, in the order they were registered.
This allows blueprints to provide default templates that can be overridden by the main application.
Extending Template Context
You can make variables or functions available to all templates without passing them manually to every render_template call.
- Context Processors: Functions decorated with
@app.context_processorreturn a dictionary of variables to be merged into the template context. - Template Filters: Functions decorated with
@app.template_filter()allow you to transform data within templates (e.g.,{{ name|reverse }}). - Template Tests: Functions decorated with
@app.template_test()allow for custom logic inifstatements (e.g.,{% if value is boolean %}). - Template Globals: Functions decorated with
@app.template_global()are available as global functions in templates.
Example of a context processor from tests/test_templating.py:
@app.context_processor
def inject_value():
return {"injected_value": 42}
Streaming Templates
For large responses, stream_template and stream_template_string return an iterator that yields the rendered template in chunks. This is useful for improving perceived performance by sending the initial HTML (like the <head>) before the entire page is rendered.
@app.route("/stream")
def stream():
return stream_template("large_page.html", data=generate_large_data())
JSON Handling
Flask provides the jsonify function and a flexible JSONProvider architecture for handling JSON data.
The jsonify Function
The jsonify function (in src/flask/json/__init__.py) serializes Python objects to JSON and returns a Response object with the application/json mimetype.
Example from examples/javascript/js_example/views.py:
@app.route("/add", methods=["POST"])
def add():
a = request.json["a"]
b = request.json["b"]
return jsonify(result=a + b)
Note: jsonify accepts either positional arguments or keyword arguments, but not both. If multiple positional arguments are provided, they are serialized as a JSON array.
JSONProvider Architecture
JSON behavior is managed by a JSONProvider instance assigned to app.json. By default, Flask uses DefaultJSONProvider (in src/flask/json/provider.py), which uses Python's built-in json module but adds support for several common types:
datetime.datetimeanddatetime.date: Serialized to RFC 822 strings (HTTP date format).uuid.UUID: Serialized to its string representation.dataclasses.dataclass: Serialized usingdataclasses.asdict.- Markup objects: Objects with an
__html__method (like those frommarkupsafe) are converted to strings.
Customizing JSON Serialization
You can customize how JSON is handled by subclassing DefaultJSONProvider and assigning it to app.json.
Example of a custom provider from tests/test_json.py:
class CustomProvider(DefaultJSONProvider):
def object_hook(self, obj):
if len(obj) == 1 and "_foo" in obj:
return X(obj["_foo"])
return obj
def loads(self, s, **kwargs):
kwargs.setdefault("object_hook", self.object_hook)
return super().loads(s, **kwargs)
app.json = CustomProvider(app)
Configuration and Debugging
Several configuration options affect templating and JSON behavior:
TEMPLATES_AUTO_RELOAD: If enabled, the Jinja environment will check for template source changes and reload them. By default, this is enabled when the app is in debug mode.EXPLAIN_TEMPLATE_LOADING: When set toTrue, Flask logs detailed information about how it attempts to locate templates, which is invaluable for debuggingTemplateNotFounderrors.JSON_SORT_KEYS: (Controlled viaapp.json.sort_keys) Determines if keys in JSON objects are sorted alphabetically. This isTrueby default inDefaultJSONProvider.
In debug mode, jsonify output is automatically pretty-printed with indentation for better readability. This is controlled by the compact attribute on the JSONProvider.