我正在使用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不同?
答案 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))
食谱中还有另一个例子: