如何防止Flask/SQLAlchemy模型中的循環引用?

2024-10-01 07:21:56 发布

您现在位置:Python中文网/ 问答频道 /正文

在我的Flask/SQLAlchemy应用程序中有以下四个模型类(第五个类MyClassA未在此处显示,而是作为参考):

class MyClassF(db.Model):
    valid_fs = ['F1', 'F2']
    f_id = db.Column(db.Integer, nullable=False, primary_key=True)
    name = db.Column(db.Enum(*valid_fs, name='f_enum'), default='F1', nullable=False)

class MyClassD(db.Model):
    d_id = db.Column(db.Integer, nullable=False, primary_key=True)
    name = db.Column(db.String(128))
    v_collection = db.relationship('MyClassV', lazy='dynamic', backref=db.backref('d'), cascade='all, delete-orphan')

class MyClassV(db.Model):
    v_id = db.Column(db.Integer, nullable=False, primary_key=True)
    d_id = db.Column(db.Integer, db.ForeignKey(MyClassD.d_id), nullable=False)
    c_collection = db.relationship('MyClassC', lazy='dynamic', backref=db.backref('v'), cascade='all, delete-orphan')
    a_collection = db.relationship('MyClassA', lazy='dynamic', backref=db.backref('v'), cascade='all, delete-orphan')

class MyClassC(db.Model):
    c_id = db.Column(db.Integer, nullable=False, primary_key=True)
    v_id = db.Column(db.Integer, db.ForeignKey(MyClassV.v_id), nullable=False)
    f_id = db.Column(
        db.Integer,
        db.ForeignKey(MyClassF.f_id),
        nullable=False,
        #default=MyClassF.query.filter(MyClassF.name == "F1").one().f_id
    )

使用Flask-Migrate命令db initdb migratedb upgrade创建这个模式很好。在

但是,当我取消注释MyClassC.f_id的定义并重试(删除migrations目录后),我得到以下循环依赖错误:

sqlalchemy.exc.InvalidRequestError: When initializing mapper Mapper|MyClassV|my_classV, expression 'MyClassC' failed to locate a name ("name 'MyClassC' is not defined"). If this is a class name, consider adding this relationship() to the class after both dependent classes have been defined.

我所要做的就是确保通过查询MyClassF表来设置MyClassC.f_id的默认值。此检查应该在插入时进行,而不是在创建数据库时进行。所以我不明白为什么我现在会犯这个错误。在

在执行循环完整性规则时,{I>如何实现循环依赖性^ 9?在


Tags: keynameidfalsetruedbmodelcolumn
1条回答
网友
1楼 · 发布于 2024-10-01 07:21:56

我相信默认参数被转换为SQL ^{} constraint。AFAICT在插入时不计算此约束,但在创建表时,该值将用作默认值(这意味着默认值在创建表时一次性设置并用于所有缺少该列的行,它不能根据其他表的内容动态更改)。在

但是the documentation of SQLAlchemy提到了这样一个事实:您可以将python函数作为默认值传入,并且每次插入都会调用它以获取要使用的默认值,因此您可以执行以下操作:

class MyClassC(db.Model):
    c_id = db.Column(db.Integer, nullable=False, primary_key=True)
    v_id = db.Column(db.Integer, db.ForeignKey(MyClassV.v_id), nullable=False)
    f_id = db.Column(
        db.Integer,
        db.ForeignKey(MyClassF.f_id),
        nullable=False,
        default=lambda: MyClassF.query.filter(MyClassF.name == "F1").one().f_id
    )

但是请注意,这将使用任何数据库工具来提供默认值,这是SQLAlchemy首先获取默认值,然后手动将其插入查询中。在

相关问题 更多 >