JSON & Data Serialization
To customize how data is serialized to and from JSON in this project, you can use the JSONProvider system for general application data or the TaggedJSONSerializer for session-specific data.
Customizing Application JSON Behavior
You can customize JSON serialization by subclassing DefaultJSONProvider and assigning it to app.json. This allows you to handle custom Python types or modify the underlying json.dumps and json.loads behavior.
from flask import Flask
from flask.json.provider import DefaultJSONProvider
class MyCustomType:
def __init__(self, value):
self.value = value
class CustomJSONProvider(DefaultJSONProvider):
def default(self, o):
if isinstance(o, MyCustomType):
return {"_type": "MyCustomType", "value": o.value}
return super().default(o)
def loads(self, s, **kwargs):
# Example of adding an object_hook to loads
def object_hook(obj):
if obj.get("_type") == "MyCustomType":
return MyCustomType(obj["value"])
return obj
kwargs.setdefault("object_hook", object_hook)
return super().loads(s, **kwargs)
app = Flask(__name__)
app.json = CustomJSONProvider(app)
The DefaultJSONProvider already includes support for several common types:
datetime.datetimeanddatetime.date(serialized to RFC 822 strings viawerkzeug.http.http_date)uuid.UUID(serialized to strings)dataclasses.dataclass(serialized viadataclasses.asdict)markupsafe.Markup(serialized via its__html__method)
Using jsonify for Responses
The jsonify function uses the application's configured JSONProvider to create a response with the application/json mimetype.
from flask import jsonify
@app.route("/data")
def get_data():
# Supports positional arguments for lists
return jsonify(1, 2, 3)
# Or keyword arguments for dicts
# return jsonify(id=1, name="Flask")
Tagged Serialization for Complex Types
For scenarios like session management where you need to preserve Python types across serialization (lossless serialization), use the TaggedJSONSerializer. This serializer uses "tags" to mark types that are not standard JSON.
To add support for a custom type in the session, create a subclass of JSONTag and register it with the session interface's serializer.
from flask import Flask
from flask.json.tag import JSONTag, TaggedJSONSerializer
class User:
def __init__(self, name):
self.name = name
class TagUser(JSONTag):
key = " u" # Unique tag key
def check(self, value):
return isinstance(value, User)
def to_json(self, value):
# Convert Python object to a JSON-serializable format
return self.serializer.tag(value.name)
def to_python(self, value):
# Convert JSON-serializable format back to Python object
return User(value)
app = Flask(__name__)
# Register the tag with the session serializer
app.session_interface.serializer.register(TagUser)
The TaggedJSONSerializer includes default tags for:
dict(tagged asdiif it contains a key that looks like a tag)tuple(tagged ast)bytes(tagged asband base64 encoded)Markup(tagged asm)UUID(tagged asu)datetime(tagged asd)
Global JSON Functions
The flask.json module provides dumps, dump, loads, and load functions that automatically use the current application's JSONProvider if an application context is active.
from flask import json
# Uses app.json.dumps if inside an app context
data = {"key": "value"}
json_string = json.dumps(data)
# Uses app.json.loads if inside an app context
original_data = json.loads(json_string)
Troubleshooting and Configuration
- App Context Requirement: Functions in
flask.json(likedumpsandloads) andjsonifyrequire an active application context to use the customapp.jsonprovider. If no context is active, they fall back to the default Pythonjsonmodule behavior. - Sorting and ASCII: You can control global JSON behavior via
DefaultJSONProviderattributes or app configuration:DefaultJSONProvider.sort_keys(defaults toTrue): Controls whether keys are sorted alphabetically.DefaultJSONProvider.ensure_ascii(defaults toTrue): Controls whether non-ASCII characters are escaped.
- Registration Order: When using
TaggedJSONSerializer.register, theindexparameter is important if one tag'scheckmethod might return true for a value that another tag should handle (e.g., a subclass). Useindex=0to prioritize a specific tag. - Removed Parameter: The
appparameter was removed fromflask.json.dumpsandflask.json.loadsin version 2.3. These functions now rely entirely oncurrent_app.