如何为SQLAlchemy模型动态生成棉花糖模式 [英] How to dynamically generate marshmallow schemas for SQLAlchemy models

查看:69
本文介绍了如何为SQLAlchemy模型动态生成棉花糖模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用SQLAlchemy模型创建Flask API.我不想为我拥有的每个模型定义一个架构,我不想每次都这样做:

I'm creating a Flask API using SQLAlchemy models. I don't want to define a schema for every model I have, I don't want to do this every time:

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

我希望每个模型都具有一个架构,因此它可以轻松地进行自身转储.创建默认模式并设置Schema.Meta.model无效:

I would like each model to have a schema, so it can easily dump itself. Creating a default Schema and setting the Schema.Meta.model didn't work:

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

为什么覆盖了模型的通用模式不同于声明了模型的模式?

Why is a generic Schema with the model overwritten different than a Schema with the model declared?

推荐答案

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

You could create a class decorator that adds the Schema to your models:

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 .

您最初尝试失败的原因是使用

The reason your original attempt fails is that marshmallow Schema classes are constructed using a custom metaclass, which inspects the namespace created from executing the class body and does its thing. When you modify the already constructed class, it is too late.

如果您不熟悉Python中的元类,请在语言参考.它们是允许发生重大事情和造成严重误用的工具.

If you're unfamiliar with metaclasses in Python, read about them in the language reference. They are a tool that allows for great things and great misuse.

一些更复杂的类型(例如枚举)需要附加信息和专用字段类型才能正常工作.例如使用棉花糖枚举和一个装饰器工厂模式,可以配置模型架构以容纳枚举:

Some more complex types, such as enums, require additional information and dedicated field types to work properly. For example using marshmallow-enum and a decorator factory pattern it is possible to configure the model schema to accommodate enums:

from marshmallow_enum import EnumField

def add_schema(**kwgs):
    def decorator(cls): 
        class Meta:
            model = cls

        schema = type("Schema", (ma.ModelSchema,), {"Meta": Meta, **kwgs})
        cls.Schema = schema
        return cls

    return decorator

...


@add_schema(
    my_enum=EnumField(MyEnumType, by_value=True)
)
class Entry(db.Model):
    ...

当然,另一种方式是使装饰器本身更聪明并在构建架构之前检查该类,以便它处理诸如枚举之类的特殊情况.

Of course another way would be to make the decorator itself smarter and inspect the class before building the schema, so that it handles special cases such as enums.

这篇关于如何为SQLAlchemy模型动态生成棉花糖模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆