08月18, 2020

Falsk 与sqlalchemy集成,主从表级联删除

Flask 开发API接口时,使用flask-restfull 具有简洁的接口,通过将SQLAlchemy和marshmallow集成在Flask,可以方便得对数据库增删查改。

问题一:flask-marshmallow-sqlalchemy集成

在项目中使用了flask-marshmallowmarshmallow-sqlalchemy插件,需要简单的配置才能使用

from flask import Flask
from flask_marshmallow import Marshmallow
# 这里注意先后顺序
app = Flask(__name__)
ma = Marshmallow(app)

或者

ma = Marshmallow()
db.init_app(app)
ma.init_app(app)

问题二:定义ModelSchema

ModelSchema是marshmallow-sqlalchemy提供的子类,可以自动根据表的定义生成field,类似于djangorestframework中的Serializer,通过ma.Nested定义主从结构,可以自动完成JSON中复杂结构的主从表保存和序列化。


class DocAnnotationSchema(ma.ModelSchema):
    class Meta:
        fields = ["id", "start_offset","end_offset","text_span","replacement",'label',"priority","ndocs"]
        model = ClaimAnnotation
        sqla_session = db.session

class ClaimDocChildSchema(ma.ModelSchema):
    annotations = ma.Nested(DocAnnotationSchema, many=True)
    class Meta:
        fields = ["id","category_id","name","text","annotations"]
        model = ClaimDoc
        sqla_session = db.session

问题三:主从表级联删除

当需要通过一个API删除主从表,需要在sqlalchemy 中model中定义cascade 属性

选项1(首选)

其次,SqlAlchemy支持两种不同的级联。 第一个,也是我建议的那个,内置在您的数据库中,通常采用外键声明约束的形式。 在PostgreSQL中它看起来像这样:

CONSTRAINT child_parent_id_fkey FOREIGN KEY (parent_id)
REFERENCES parent_table(id) MATCH SIMPLE
ON DELETE CASCADE

这意味着当您从parent_table删除记录时, parent_table您删除parent_table所有相应行。 它快速可靠,可能是您最好的选择。 你可以通过ForeignKey在SqlAlchemy中设置它(这是子表定义的一部分):

parent_id = db.Column(db.Integer, db.ForeignKey('parent.id', ondelete='CASCADE'))
parent = db.relationship('Parent', backref=backref('children', passive_deletes=True))

ondelete='CASCADE'是在表上创建ON DELETE CASCADE的部分。

使用passive_deletes=True指定relationship ? 如果你没有,整个事情都行不通。 这是因为默认情况下,当您删除父记录时,SqlAlchemy会做一些非常奇怪的事情。 它将所有子行的外键设置为NULL 。 因此,如果从parent_table中删除id = 5的行,那么它将基本执行

UPDATE child_table SET parent_id = NULL WHERE parent_id = 5

选项2

另一种方法是让SqlAlchemy为你做。 这是使用relationship的cascade参数设置的。 如果您在父表上定义了关系,它看起来像这样:

children = relationship('Child', cascade='all,delete', backref='parent')

如果关系在孩子身上,你可以这样做:

parent = relationship('Parent', backref=backref('children', cascade='all,delete'))

同样,这是孩子所以你必须调用一个名为backref的方法并将级联数据放在那里。

本文链接:http://57km.cc/post/flask integration with sqlalchemy.html

-- EOF --

Comments