我在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 init
,db migrate
和db upgrade
创建此架构的工作正常。
但是,当我取消注释行MyClassC.f_id
的定义并再次尝试(删除migrations
目录后)时,我得到以下循环依赖性错误:
sqlalchemy.exc.InvalidRequestError:初始化mapper时 Mapper | MyClassV | my_classV,表达式'MyClassC'找不到 name(“name'MyClassC'未定义”)。如果这是一个类名, 考虑将此关系()添加到 在定义了两个依赖类之后的类。
我要做的就是确保通过查询MyClassC.f_id
表来设置默认值MyClassF
。此检查应在插入时进行 - 而不是在创建数据库时进行。所以我不明白为什么我现在收到这个错误。
如何在执行我正在尝试实施的数据库完整性规则时,使用db.relationship()
(或任何其他技术)来解决此循环依赖性错误?
答案 0 :(得分:3)
我相信默认参数会转换为SQL DEFAULT
constraint。 AFAICT此约束不会在插入时进行评估,但在创建表时,该值将用作默认值(这意味着默认值设置一次,并且在创建表时使用forall并用于缺少该列的所有行,它不能根据其他表的内容动态改变)。
但是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首先获取默认值,然后手动将其插入查询中。