1*********************************************************
2Flask-Marshmallow: Flask + marshmallow for beautiful APIs
3*********************************************************
4
5:ref:`changelog <changelog>` //
6`github <http://github.com/marshmallow-code/flask-marshmallow>`_ //
7`pypi <http://pypi.python.org/pypi/flask-marshmallow>`_ //
8`issues <http://github.com/marshmallow-code/flask-marshmallow/issues>`_
9
10
11Flask + marshmallow for beautiful APIs
12======================================
13
14Flask-Marshmallow is a thin integration layer for `Flask`_ (a Python web framework) and `marshmallow`_ (an object serialization/deserialization library) that adds additional features to marshmallow, including URL and Hyperlinks fields for HATEOAS-ready APIs. It also (optionally) integrates with `Flask-SQLAlchemy <http://flask-sqlalchemy.pocoo.org/>`_.
15
16Get it now
17----------
18::
19
20    pip install flask-marshmallow
21
22
23Create your app.
24
25.. code-block:: python
26
27    from flask import Flask
28    from flask_marshmallow import Marshmallow
29
30    app = Flask(__name__)
31    ma = Marshmallow(app)
32
33Write your models.
34
35.. code-block:: python
36
37    from your_orm import Model, Column, Integer, String, DateTime
38
39
40    class User(Model):
41        email = Column(String)
42        password = Column(String)
43        date_created = Column(DateTime, auto_now_add=True)
44
45
46Define your output format with marshmallow.
47
48.. code-block:: python
49
50
51    class UserSchema(ma.Schema):
52        class Meta:
53            # Fields to expose
54            fields = ("email", "date_created", "_links")
55
56        # Smart hyperlinking
57        _links = ma.Hyperlinks(
58            {
59                "self": ma.URLFor("user_detail", values=dict(id="<id>")),
60                "collection": ma.URLFor("users"),
61            }
62        )
63
64
65    user_schema = UserSchema()
66    users_schema = UserSchema(many=True)
67
68
69Output the data in your views.
70
71.. code-block:: python
72
73    @app.route("/api/users/")
74    def users():
75        all_users = User.all()
76        return users_schema.dump(all_users)
77
78
79    @app.route("/api/users/<id>")
80    def user_detail(id):
81        user = User.get(id)
82        return user_schema.dump(user)
83
84
85    # {
86    #     "email": "fred@queen.com",
87    #     "date_created": "Fri, 25 Apr 2014 06:02:56 -0000",
88    #     "_links": {
89    #         "self": "/api/users/42",
90    #         "collection": "/api/users/"
91    #     }
92    # }
93
94
95
96Optional Flask-SQLAlchemy Integration
97-------------------------------------
98
99Flask-Marshmallow includes useful extras for integrating with `Flask-SQLAlchemy <http://flask-sqlalchemy.pocoo.org/>`_ and `marshmallow-sqlalchemy <https://marshmallow-sqlalchemy.readthedocs.io>`_.
100
101To enable SQLAlchemy integration, make sure that both Flask-SQLAlchemy and marshmallow-sqlalchemy are installed.  ::
102
103    pip install -U flask-sqlalchemy marshmallow-sqlalchemy
104
105Next, initialize the `~flask_sqlalchemy.SQLAlchemy` and `~flask_marshmallow.Marshmallow` extensions, in that order.
106
107.. code-block:: python
108
109    from flask import Flask
110    from flask_sqlalchemy import SQLAlchemy
111    from flask_marshmallow import Marshmallow
112
113    app = Flask(__name__)
114    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:////tmp/test.db"
115
116    # Order matters: Initialize SQLAlchemy before Marshmallow
117    db = SQLAlchemy(app)
118    ma = Marshmallow(app)
119
120.. admonition:: Note on initialization order
121
122    Flask-SQLAlchemy **must** be initialized before Flask-Marshmallow.
123
124
125Declare your models like normal.
126
127
128.. code-block:: python
129
130    class Author(db.Model):
131        id = db.Column(db.Integer, primary_key=True)
132        name = db.Column(db.String(255))
133
134
135    class Book(db.Model):
136        id = db.Column(db.Integer, primary_key=True)
137        title = db.Column(db.String(255))
138        author_id = db.Column(db.Integer, db.ForeignKey("author.id"))
139        author = db.relationship("Author", backref="books")
140
141
142Generate marshmallow `Schemas <marshmallow.Schema>` from your models using `~flask_marshmallow.sqla.SQLAlchemySchema` or `~flask_marshmallow.sqla.SQLAlchemyAutoSchema`.
143
144.. code-block:: python
145
146    class AuthorSchema(ma.SQLAlchemySchema):
147        class Meta:
148            model = Author
149
150        id = ma.auto_field()
151        name = ma.auto_field()
152        books = ma.auto_field()
153
154
155    class BookSchema(ma.SQLAlchemyAutoSchema):
156        class Meta:
157            model = Book
158            include_fk = True
159
160You can now use your schema to dump and load your ORM objects.
161
162
163.. code-block:: python
164
165    db.create_all()
166    author_schema = AuthorSchema()
167    book_schema = BookSchema()
168    author = Author(name="Chuck Paluhniuk")
169    book = Book(title="Fight Club", author=author)
170    db.session.add(author)
171    db.session.add(book)
172    db.session.commit()
173    author_schema.dump(author)
174    # {'id': 1, 'name': 'Chuck Paluhniuk', 'books': [1]}
175
176
177`~flask_marshmallow.sqla.SQLAlchemySchema` is nearly identical in API to `marshmallow_sqlalchemy.SQLAlchemySchema` with the following exceptions:
178
179- By default, `~flask_marshmallow.sqla.SQLAlchemySchema` uses the scoped session created by Flask-SQLAlchemy.
180- `~flask_marshmallow.sqla.SQLAlchemySchema` subclasses `flask_marshmallow.Schema`, so it includes the `~flask_marshmallow.Schema.jsonify` method.
181Note: By default, Flask's `jsonify` method sorts the list of keys and returns consistent results to ensure that external HTTP caches aren't trashed. As a side effect, this will override `ordered=True <https://marshmallow.readthedocs.io/en/latest/quickstart.html#ordering-output>`_
182in the SQLAlchemySchema's `class Meta` (if you set it). To disable this, set `JSON_SORT_KEYS=False` in your Flask app config. In production it's recommended to let `jsonify` sort the keys and not set `ordered=True` in your `~flask_marshmallow.sqla.SQLAlchemySchema` in order to minimize generation time and maximize cacheability of the results.
183
184You can also use `ma.HyperlinkRelated <flask_marshmallow.sqla.HyperlinkRelated>` fields if you want relationships to be represented by hyperlinks rather than primary keys.
185
186
187.. code-block:: python
188
189    class BookSchema(ma.SQLAlchemyAutoSchema):
190        class Meta:
191            model = Book
192
193        author = ma.HyperlinkRelated("author_detail")
194
195.. code-block:: python
196
197    with app.test_request_context():
198        print(book_schema.dump(book))
199    # {'id': 1, 'title': 'Fight Club', 'author': '/authors/1'}
200
201The first argument to the `~flask_marshmallow.sqla.HyperlinkRelated` constructor is the name of the view used to generate the URL, just as you would pass it to the `~flask.url_for` function. If your models and views use the ``id`` attribute
202as a primary key, you're done; otherwise, you must specify the name of the
203attribute used as the primary key.
204
205To represent a one-to-many relationship, wrap the `~flask_marshmallow.sqla.HyperlinkRelated` instance in a `marshmallow.fields.List` field, like this:
206
207.. code-block:: python
208
209    class AuthorSchema(ma.SQLAlchemyAutoSchema):
210        class Meta:
211            model = Author
212
213        books = ma.List(ma.HyperlinkRelated("book_detail"))
214
215.. code-block:: python
216
217    with app.test_request_context():
218        print(author_schema.dump(author))
219    # {'id': 1, 'name': 'Chuck Paluhniuk', 'books': ['/books/1']}
220
221
222API
223===
224
225.. automodule:: flask_marshmallow
226    :members:
227
228.. automodule:: flask_marshmallow.fields
229    :members:
230
231.. automodule:: flask_marshmallow.sqla
232    :members:
233
234
235Useful Links
236============
237
238- `Flask docs`_
239- `marshmallow docs`_
240
241.. _marshmallow docs: http://marshmallow.readthedocs.io
242
243.. _Flask docs: http://flask.pocoo.org/docs/
244
245Project Info
246============
247
248.. toctree::
249   :maxdepth: 1
250
251   license
252   changelog
253
254
255.. _marshmallow: http://marshmallow.readthedocs.io
256
257 .. _Flask: http://flask.pocoo.org
258