1
+ """Flask application JSON extension functions."""
2
+ from functools import lru_cache
3
+
1
4
from bson import DBRef , ObjectId , json_util
2
- from flask .json import JSONEncoder
3
5
from mongoengine .base import BaseDocument
4
6
from mongoengine .queryset import QuerySet
5
7
from pymongo .command_cursor import CommandCursor
6
8
7
9
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
+
8
19
def _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
+
9
32
class MongoEngineJSONEncoder (superclass ):
10
33
"""
11
34
A JSONEncoder which provides serialization of MongoEngine
12
35
documents and queryset objects.
13
36
"""
14
37
38
+ # noinspection PyProtectedMember, DuplicatedCode
15
39
def default (self , obj ):
40
+ """Extend JSONEncoder default method, with Mongo objects."""
16
41
if isinstance (obj , BaseDocument ):
17
42
return json_util ._json_convert (obj .to_mongo ())
18
43
elif isinstance (obj , QuerySet ):
@@ -28,7 +53,44 @@ def default(self, obj):
28
53
return MongoEngineJSONEncoder
29
54
30
55
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
32
94
33
95
34
96
def override_json_encoder (app ):
@@ -42,4 +104,9 @@ def override_json_encoder(app):
42
104
NOTE: This does not cover situations where users override
43
105
an instance's json_encoder after calling init_app.
44
106
"""
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