[使用Peewee时,我遵循Create "query methods" in Peewee Models Python答案的建议:
class Person(Model):
name = CharField()
age = IntegerField()
@classmethod
def adults(cls):
return cls.select().where(cls.age > 18)
我为所有查询创建类方法,以使模型保持“胖”状态,并使其他所有内容保持“稀疏”状态。现在,我介绍了一个外键,并且我在尝试这种方法,因为Peewee要求我直接在查询中使用模型类:
class Metric(Model):
person = ForeignKeyField(Person, backref='metrics')
name = CharField()
value = IntegerField()
其他文件:
class Person(Model):
name = CharField()
age = IntegerField()
@classmethod
def popular(cls, min_likes):
return cls.select(cls, Metric).join(Metric).where(Metric.name == 'likes', Metric.value > min_likes)
这将不起作用,因为Metric
的定义取决于Person
,反之亦然,导致循环导入。该文档有一个Circular foreign key dependencies部分,其中类似情况的解决方案是DeferredForeignKey
,但我不喜欢它,因为它增加了代码开销(需要在任何地方手动创建外键),并且因为我的应用程序正在使用SQLite-文档明确声明以下内容:
因为SQLite对更改表的支持有限,所以在创建表后不能将外键约束添加到表中。
如果我理解正确,那实际上意味着我实际上将完全失去FK约束。不过,我需要约束,该应用程序依赖于缺少对应项的记录会引发异常的事实。
我正在忽略其他解决方法吗?毕竟,在Peewee中推荐这样的胖模型吗?我喜欢它,但是这让我陷入了模型设计的死胡同。文档甚至说:
我个人的看法是,圆形外键是代码的味道,应该进行重构(例如,通过添加中间表)。
Update:我最初更新了问题,无意中省略了主要细节:我正在处理循环imports,而不仅仅是类之间的dependencies。如果我将类并置到一个文件中,它将可以正常工作,因为Python仅在调用它们时才在类方法中解析名称,但这不是我要解决的问题,我想将类保留在单独的模块中。
# Move metric below Person.
class Person(Model):
name = CharField()
age = IntegerField()
@classmethod
def popular(cls, min_likes):
return cls.select(cls, Metric).join(Metric).where(Metric.name == 'likes', Metric.value > min_likes)
class Metric(Model):
person = ForeignKeyField(Person, backref='metrics')
name = CharField()
value = IntegerField()
或者,您可以使用为此目的而[构建的DeferredForeignKey
。