/
__init__.py
executable file
·131 lines (101 loc) · 3.59 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""
flask_marshmallow
~~~~~~~~~~~~~~~~~
Integrates the marshmallow serialization/deserialization library
with your Flask application.
"""
import typing
import warnings
from marshmallow import exceptions, pprint
from marshmallow import fields as base_fields
from . import fields
from .schema import Schema
if typing.TYPE_CHECKING:
from flask import Flask
has_sqla = False
try:
import flask_sqlalchemy # noqa: F401
except ImportError:
has_sqla = False
else:
try:
from . import sqla
except ImportError:
warnings.warn(
"Flask-SQLAlchemy integration requires "
"marshmallow-sqlalchemy to be installed.",
stacklevel=2,
)
else:
has_sqla = True
__all__ = [
"EXTENSION_NAME",
"Marshmallow",
"Schema",
"fields",
"exceptions",
"pprint",
]
EXTENSION_NAME = "flask-marshmallow"
def _attach_fields(obj):
"""Attach all the marshmallow fields classes to ``obj``, including
Flask-Marshmallow's custom fields.
"""
for attr in base_fields.__all__:
if not hasattr(obj, attr):
setattr(obj, attr, getattr(base_fields, attr))
for attr in fields.__all__:
setattr(obj, attr, getattr(fields, attr))
class Marshmallow:
"""Wrapper class that integrates Marshmallow with a Flask application.
To use it, instantiate with an application::
from flask import Flask
app = Flask(__name__)
ma = Marshmallow(app)
The object provides access to the :class:`Schema` class,
all fields in :mod:`marshmallow.fields`, as well as the Flask-specific
fields in :mod:`flask_marshmallow.fields`.
You can declare schema like so::
class BookSchema(ma.Schema):
class Meta:
fields = ("id", "title", "author", "links")
author = ma.Nested(AuthorSchema)
links = ma.Hyperlinks(
{
"self": ma.URLFor("book_detail", values=dict(id="<id>")),
"collection": ma.URLFor("book_list"),
}
)
In order to integrate with Flask-SQLAlchemy, this extension must be initialized
*after* `flask_sqlalchemy.SQLAlchemy`. ::
db = SQLAlchemy(app)
ma = Marshmallow(app)
This gives you access to `ma.SQLAlchemySchema` and `ma.SQLAlchemyAutoSchema`, which
generate marshmallow `~marshmallow.Schema` classes
based on the passed in model or table. ::
class AuthorSchema(ma.SQLAlchemyAutoSchema):
class Meta:
model = Author
:param Flask app: The Flask application object.
"""
def __init__(self, app: typing.Optional["Flask"] = None):
self.Schema = Schema
if has_sqla:
self.SQLAlchemySchema = sqla.SQLAlchemySchema
self.SQLAlchemyAutoSchema = sqla.SQLAlchemyAutoSchema
self.auto_field = sqla.auto_field
self.HyperlinkRelated = sqla.HyperlinkRelated
_attach_fields(self)
if app is not None:
self.init_app(app)
def init_app(self, app: "Flask"):
"""Initializes the application with the extension.
:param Flask app: The Flask application object.
"""
app.extensions = getattr(app, "extensions", {})
# If using Flask-SQLAlchemy, attach db.session to SQLAlchemySchema
if has_sqla and "sqlalchemy" in app.extensions:
db = app.extensions["sqlalchemy"]
self.SQLAlchemySchema.OPTIONS_CLASS.session = db.session
self.SQLAlchemyAutoSchema.OPTIONS_CLASS.session = db.session
app.extensions[EXTENSION_NAME] = self