1

我的 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 migrate并且db upgrade工作正常。

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

sqlalchemy.exc.InvalidRequestError:初始化映射器 Mapper|MyClassV|my_classV 时,表达式 'MyClassC' 未能找到名称(“名称 'MyClassC' 未定义”)。如果这是一个类名,请考虑在定义了两个依赖类之后将此 relationship() 添加到该类中。

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

db.relationship()在执行我试图实现的数据库完整性规则时,如何使用(或任何其他技术)来解决这个循环依赖错误?

4

1 回答 1

3

我相信默认参数被转换为SQLDEFAULT约束。AFAICT 此约束不会在插入时进行评估,但在创建表时将该值用作默认值(这意味着默认值在创建表时设置一次并用于所有缺少该列的行,它不能根据另一个表的内容动态改变)。

然而,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 首先获取默认值,然后手动将其插入到您的查询中。

于 2016-11-07T08:16:12.460 回答