Python
  • index
  • Basic - 1
  • Basic - 2
  • SQLAlchemy
  • Decorator
  • @property
  • __dict__
  • pathlib
  • class
  • flask
  • Jupyter Notebook
  • PyQt
  • UD - FLASK - PY Basic
  • UD - FLASK - REST
  • UD - FLASK - vanilla SQL
  • UD - FLASK - SQLAlchemy
  • UD - FLASK - JWT
  • UD - FLASK - Serialization
Powered by GitBook
On this page
  • 1. Vanilla marshmallow
  • 1.1. Serialization -> dict
  • 1.2. Deserialization -> object
  • 2. Flask-marshmallow
  • 2.1. Components
  • 2.2. Nested schema

Was this helpful?

UD - FLASK - Serialization

why serialization

  • easier serialization / deserialization

  • separate model from data interaction

  • whitelist params

json & reqparse are no longer required.

1. Vanilla marshmallow

core

from marshmallow import Schema, fields

class BookSchema(Schema):
    title = fields.Str()
    author = fields.Str()

class Book:
    def __init__(self, title, author, description):
        self.title = title
        self.author = author
        self.description = description

1.1. Serialization -> dict

book = Book('Clean Code', 'Bob Martin', 'This is a good book!')

book_schema = BookSchema()
book_dict = book_schema.dump(book)

print(book_dict) # {'title': 'Clean Code', 'author': 'Bob Martin'} # no description params

1.2. Deserialization -> object

incoming_book_data = {
    "title": "Clean Code",
    "author": "Bob Martin",
    "description": "A book about writing cleaner code, with examples in Java",
}

book_schema = BookSchema()
book = book_schema.load(incoming_book_data) # dict
book_obj = Book(**book) # obj

print(book_obj.title) # Clean Code

2. Flask-marshmallow

  1. schema will load json to object directly.

  2. tight integration between schema & model; fields only declare in one place.

  3. init& json methods are no longer required in model.

  4. reqparse method is no longer required in resource.

book_obj = book_schema.load(incoming_book_data) # obj

2.1. Components

# ma.py
from flask_marshmallow import Marshmallow

ma = Marshmallow()
# app.py
from ma import ma

if __name__ == "__main__":
    db.init_app(app)
    ma.init_app(app)
    app.run(port=5000, debug=True)

model (no marshmallow here)

# /models/item.py
from typing import List
from db import db


class ItemModel(db.Model):
    __tablename__ = "items"

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(80), nullable=False, unique=True)
    price = db.Column(db.Float(precision=2), nullable=False)

    store_id = db.Column(db.Integer, db.ForeignKey("stores.id"), nullable=False)
    store = db.relationship("StoreModel")

    # no __init__ method

    @classmethod
    def find_by_name(cls, name: str) -> "ItemModel":
        return cls.query.filter_by(name=name).first()

    @classmethod
    def find_all(cls) -> List["ItemModel"]:
        return cls.query.all()

    def save_to_db(self) -> None:
        db.session.add(self)
        db.session.commit()

    def delete_from_db(self) -> None:
        db.session.delete(self)
        db.session.commit()

schema (fields are defined by models)

# /schemas/item.py
from ma import ma
from models.item import ItemModel
from models.store import StoreModel

class ItemSchema(ma.ModelSchema):
    class Meta:
        model = ItemModel
        load_only = ("store",)
        dump_only = ("id",)
        include_fk = True # store_id

resource

from models.item import ItemModel
from schemas.item import ItemSchema

item_schema = ItemSchema()
item_list_schema = ItemSchema(many=True)


class Item(Resource):
    @classmethod
    def get(cls, name: str):
        item = ItemModel.find_by_name(name)
        if item:
            return item_schema.dump(item), 200 # dump to json

        return {"message": ITEM_NOT_FOUND}, 404

    @classmethod
    @fresh_jwt_required
    def post(cls, name: str):
        if ItemModel.find_by_name(name):
            return {"message": NAME_ALREADY_EXISTS.format(name)}, 400

        item_json = request.get_json()
        item_json["name"] = name

        item = item_schema.load(item_json) # load to object

        try:
            item.save_to_db()
        except:
            return {"message": ERROR_INSERTING}, 500

        return item_schema.dump(item), 201
    ...

class ItemList(Resource):
    @classmethod
    def get(cls):
        return {"items": item_list_schema.dump(ItemModel.find_all())}, 200 # list schema

2.2. Nested schema

# /schema/store.py
from ma import ma
from models.store import StoreModel
from models.item import ItemModel
from schemas.item import ItemSchema


class StoreSchema(ma.ModelSchema):
    items = ma.Nested(ItemSchema, many=True) # nested

    class Meta:
        model = StoreModel
        dump_only = ("id",)
        include_fk = True
PreviousUD - FLASK - JWT

Last updated 5 years ago

Was this helpful?