如何为SQLAlchemy模型

时间:2017-03-19 19:26:34

标签: python flask sqlalchemy marshmallow

我正在使用SQLAlchemy模型创建Flask API。 我不想为每个模型定义模式,我不想每次都这样做:

class EntrySchema(ma.ModelSchema):
    class Meta:
        model = Entry

我希望每个模型都有一个模式,因此它可以轻松地自行转储。 创建默认架构并设置Schema.Meta.model不起作用:

class Entry(db.Model):
    __tablename__ = 'entries'

    id = db.Column(db.Integer, primary_key=True)
    started_at = db.Column(db.DateTime)
    ended_at = db.Column(db.DateTime)
    description = db.Column(db.Text())

    def __init__(self, data):
        for key in data:
            setattr(self, key, data[key])

        self.Schema = Schema
        self.Schema.Meta.model = self.__class__

    def dump(self):
        schema = self.Schema()
        result = schema.dump(self)
        return result


class Schema(ma.ModelSchema):
    class Meta:
        pass

为什么覆盖模型的泛型Schema与声明模型的Schema不同?

3 个答案:

答案 0 :(得分:6)

您可以创建一个类装饰器,将Schema添加到模型中:

def add_schema(cls):
    class Schema(ma.ModelSchema):
        class Meta:
            model = cls
    cls.Schema = Schema
    return cls

然后

@add_schema
class Entry(db.Model):
    ...

架构将作为类属性Entry.Schema使用。

原始尝试失败的原因是使用custom metaclass构造了marshmallow Schema类,它检查从执行类主体和does its thing创建的命名空间。修改已构建的类时,为时已晚。

如果您不熟悉Python中的元类,请在language reference中阅读它们。它们是一种工具,可以实现伟大的事物和极大的误用。

答案 1 :(得分:0)

marshmallow recipes规定了几种将常见架构选项引入基类的备选方案。这是一个直接来自文档的简单示例:

# myproject/schemas.py

from marshmallow_sqlalchemy import ModelSchema

from .db import Session

class BaseSchema(ModelSchema):
    class Meta:
        sqla_session = Session

然后扩展基础架构:

# myproject/users/schemas.py

from ..schemas import BaseSchema
from .models import User

class UserSchema(BaseSchema):

    # Inherit BaseSchema's options
    class Meta(BaseSchema.Meta):
        model = User

此方法的优点是您可以向特定模型添加更多de / serialization

链接文档的更多示例和配方

答案 2 :(得分:0)

从蛋白软糖-sqlalchemy食谱中:

  

“为SQLAlchemy模型自动生成架构   如果不覆盖任何模式,则要实现大量模式很乏味   上面详细介绍了生成的字段。 SQLAlchemy有一个钩子   可用于触发模式的创建,将其分配给   SQLAlchemy模型属性“。

我的使用flask_sqlalchemy和marshmallow_sqlalchemy的示例:

from flask_sqlalchemy import SQLAlchemy
from marshmallow_sqlalchemy import ModelConversionError, ModelSchema
from sqlalchemy import event
from sqlalchemy.orm import mapper


db = SQLAlchemy()


def setup_schema(Base, session):
    # Create a function which incorporates the Base and session information
    def setup_schema_fn():
        for class_ in Base._decl_class_registry.values():
            if hasattr(class_, "__tablename__"):
                if class_.__name__.endswith("Schema"):
                    raise ModelConversionError(
                        "For safety, setup_schema can not be used when a"
                        "Model class ends with 'Schema'"
                    )

                class Meta(object):
                    model = class_
                    sqla_session = session

                schema_class_name = "%sSchema" % class_.__name__

                schema_class = type(schema_class_name, (ModelSchema,), {"Meta": Meta})

                setattr(class_, "Schema", schema_class)

    return setup_schema_fn


event.listen(mapper, "after_configured", setup_schema(db.Model, db.session))

食谱中还有另一个例子:

https://marshmallow-sqlalchemy.readthedocs.io/en/latest/recipes.html#automatically-generating-schemas-for-sqlalchemy-models