Peewee v2.7.4中,支持外键引用直接传模型实例的特性是什么?
解答:Peewee中外键直接传入模型实例的特性
你遇到的这个情况,核心是Peewee的ForeignKeyField自带的实例到主键的隐式转换特性,不过在v2.7.4这个版本里有一些需要注意的细节,我给你梳理清楚:
为什么直接传实例有时候可行?
当你的模型通过ForeignKeyField定义外键关联时(比如ModelB里的model_a = ForeignKeyField(ModelA)),Peewee会自动处理两种传参方式:
- 给
model_a_id(自动生成的主键存储字段)传主键值(比如model_a.get_id()的结果) - 给
model_a(外键字段本身)传ModelA的实例——此时Peewee会自动提取实例的主键值,填充到model_a_id字段中
这是ForeignKeyField为了简化开发而设计的特性,避免你每次都要手动取主键。
为什么你的代码里model_a_id=model_a会失效?
在Peewee v2.7.4这个较早的版本中,直接给_id后缀的字段传模型实例是不被支持的。这个版本的字段处理逻辑里,只有外键字段本身(也就是不带_id的那个字段名)才会触发实例到主键的转换。
所以你应该把代码改成这样:
Model_b.get_or_create(name='foo', model_a=model_a)
这样就能正常工作,不需要手动调用get_id()。
额外排查点
如果改了字段名还是不行,那你要检查ModelB的定义:是不是没有用ForeignKeyField,而是手动定义了model_a_id = IntegerField()?如果是普通的IntegerField,Peewee不知道这是外键关联,自然不会帮你转换实例,必须传主键值才行。
举个正确的模型定义例子:
from peewee import Model, CharField, ForeignKeyField, SqliteDatabase db = SqliteDatabase('test.db') class ModelA(Model): name = CharField() class Meta: database = db class ModelB(Model): name = CharField() model_a = ForeignKeyField(ModelA) # 这里是关键,用ForeignKeyField定义外键 class Meta: database = db
用这个定义的话,Model_b.get_or_create(name='foo', model_a=model_a)就会正常触发实例转换。
内容的提问来源于stack exchange,提问作者Ritmo2k




