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+
819def _make_encoder (superclass ):
20+ """Extend Flask JSON Encoder 'default' method with support of Mongo objects."""
21+ import warnings
22+
23+ warnings .warn (
24+ (
25+ "JSONEncoder/JSONDecoder are deprecated in Flask 2.2 and will be removed "
26+ "in Flask 2.3."
27+ ),
28+ DeprecationWarning ,
29+ stacklevel = 2 ,
30+ )
31+
932 class MongoEngineJSONEncoder (superclass ):
1033 """
1134 A JSONEncoder which provides serialization of MongoEngine
1235 documents and queryset objects.
1336 """
1437
38+ # noinspection PyProtectedMember, DuplicatedCode
1539 def default (self , obj ):
40+ """Extend JSONEncoder default method, with Mongo objects."""
1641 if isinstance (obj , BaseDocument ):
1742 return json_util ._json_convert (obj .to_mongo ())
1843 elif isinstance (obj , QuerySet ):
@@ -28,7 +53,44 @@ def default(self, obj):
2853 return MongoEngineJSONEncoder
2954
3055
31- MongoEngineJSONEncoder = _make_encoder (JSONEncoder )
56+ def _update_json_provider (superclass ):
57+ """Extend Flask Provider 'default' static method with support of Mongo objects."""
58+
59+ class MongoEngineJSONProvider (superclass ):
60+ """A JSON Provider update for Flask 2.2.0+"""
61+
62+ # noinspection PyProtectedMember, DuplicatedCode
63+ @staticmethod
64+ def default (obj ):
65+ """Extend JSONProvider default static method, with Mongo objects."""
66+ if isinstance (obj , BaseDocument ):
67+ return json_util ._json_convert (obj .to_mongo ())
68+ elif isinstance (obj , QuerySet ):
69+ return json_util ._json_convert (obj .as_pymongo ())
70+ elif isinstance (obj , CommandCursor ):
71+ return json_util ._json_convert (obj )
72+ elif isinstance (obj , DBRef ):
73+ return obj .id
74+ elif isinstance (obj , ObjectId ):
75+ return obj .__str__ ()
76+ return super ().default (obj )
77+
78+ return MongoEngineJSONProvider
79+
80+
81+ # Compatibility code for Flask 2.2.0+ support
82+ MongoEngineJSONEncoder = None
83+ MongoEngineJSONProvider = None
84+
85+ if use_json_provider ():
86+ from flask .json .provider import DefaultJSONProvider
87+
88+ MongoEngineJSONProvider = _update_json_provider (DefaultJSONProvider )
89+ else :
90+ from flask .json import JSONEncoder
91+
92+ MongoEngineJSONEncoder = _make_encoder (JSONEncoder )
93+ # End of compatibility code
3294
3395
3496def override_json_encoder (app ):
@@ -42,4 +104,9 @@ def override_json_encoder(app):
42104 NOTE: This does not cover situations where users override
43105 an instance's json_encoder after calling init_app.
44106 """
45- app .json_encoder = _make_encoder (app .json_encoder )
107+
108+ if use_json_provider ():
109+ app .json_provider_class = _update_json_provider (app .json_provider_class )
110+ app .json = app .json_provider_class (app )
111+ else :
112+ app .json_encoder = _make_encoder (app .json_encoder )
0 commit comments