1+ """Flask application JSON extension functions."""
2+ from functools import lru_cache
3+
14from bson import DBRef , ObjectId , json_util
2- from flask .json import JSONEncoder
35from mongoengine .base import BaseDocument
46from mongoengine .queryset import QuerySet
57from pymongo .command_cursor import CommandCursor
68
79
10+ @lru_cache (maxsize = 1 )
11+ def use_json_provider () -> bool :
12+ """Split Flask before 2.2.0 and after, to use/not use JSON provider approach."""
13+ from flask import __version__
14+
15+ version = list (__version__ .split ("." ))
16+ return int (version [0 ]) > 2 or (int (version [0 ]) == 2 and int (version [1 ]) > 1 )
17+
18+
19+ # noinspection PyProtectedMember
20+ def _convert_mongo_objects (obj ):
21+ """Convert objects, related to Mongo database to JSON."""
22+ converted = None
23+ if isinstance (obj , BaseDocument ):
24+ converted = json_util ._json_convert (obj .to_mongo ())
25+ elif isinstance (obj , QuerySet ):
26+ converted = json_util ._json_convert (obj .as_pymongo ())
27+ elif isinstance (obj , CommandCursor ):
28+ converted = json_util ._json_convert (obj )
29+ elif isinstance (obj , DBRef ):
30+ converted = obj .id
31+ elif isinstance (obj , ObjectId ):
32+ converted = obj .__str__ ()
33+ return converted
34+
35+
836def _make_encoder (superclass ):
37+ """Extend Flask JSON Encoder 'default' method with support of Mongo objects."""
38+ import warnings
39+
40+ warnings .warn (
41+ (
42+ "JSONEncoder/JSONDecoder are deprecated in Flask 2.2 and will be removed "
43+ "in Flask 2.3."
44+ ),
45+ DeprecationWarning ,
46+ stacklevel = 2 ,
47+ )
48+
949 class MongoEngineJSONEncoder (superclass ):
1050 """
1151 A JSONEncoder which provides serialization of MongoEngine
1252 documents and queryset objects.
1353 """
1454
1555 def default (self , obj ):
16- if isinstance (obj , BaseDocument ):
17- return json_util ._json_convert (obj .to_mongo ())
18- elif isinstance (obj , QuerySet ):
19- return json_util ._json_convert (obj .as_pymongo ())
20- elif isinstance (obj , CommandCursor ):
21- return json_util ._json_convert (obj )
22- elif isinstance (obj , DBRef ):
23- return obj .id
24- elif isinstance (obj , ObjectId ):
25- return obj .__str__ ()
26- return superclass .default (self , obj )
56+ """Extend JSONEncoder default method, with Mongo objects."""
57+ if isinstance (
58+ obj ,
59+ (BaseDocument , QuerySet , CommandCursor , DBRef , ObjectId ),
60+ ):
61+ return _convert_mongo_objects (obj )
62+ return super ().default (obj )
2763
2864 return MongoEngineJSONEncoder
2965
3066
31- MongoEngineJSONEncoder = _make_encoder (JSONEncoder )
67+ def _update_json_provider (superclass ):
68+ """Extend Flask Provider 'default' static method with support of Mongo objects."""
69+
70+ class MongoEngineJSONProvider (superclass ):
71+ """A JSON Provider update for Flask 2.2.0+"""
72+
73+ @staticmethod
74+ def default (obj ):
75+ """Extend JSONProvider default static method, with Mongo objects."""
76+ if isinstance (
77+ obj ,
78+ (BaseDocument , QuerySet , CommandCursor , DBRef , ObjectId ),
79+ ):
80+ return _convert_mongo_objects (obj )
81+ return super ().default (obj )
82+
83+ return MongoEngineJSONProvider
84+
85+
86+ # Compatibility code for Flask 2.2.0+ support
87+ MongoEngineJSONEncoder = None
88+ MongoEngineJSONProvider = None
89+
90+ if use_json_provider ():
91+ from flask .json .provider import DefaultJSONProvider
92+
93+ MongoEngineJSONProvider = _update_json_provider (DefaultJSONProvider )
94+ else :
95+ from flask .json import JSONEncoder
96+
97+ MongoEngineJSONEncoder = _make_encoder (JSONEncoder )
98+ # End of compatibility code
3299
33100
34101def override_json_encoder (app ):
@@ -42,4 +109,9 @@ def override_json_encoder(app):
42109 NOTE: This does not cover situations where users override
43110 an instance's json_encoder after calling init_app.
44111 """
45- app .json_encoder = _make_encoder (app .json_encoder )
112+
113+ if use_json_provider ():
114+ app .json_provider_class = _update_json_provider (app .json_provider_class )
115+ app .json = app .json_provider_class (app )
116+ else :
117+ app .json_encoder = _make_encoder (app .json_encoder )
0 commit comments