Django的post_save信号对使用多表继承的模型表现得很奇怪
我注意到Django的post_save信号在使用具有多表继承的模型时的奇怪行为。
我有这两个模型:
class Animal(models.Model):
category = models.CharField(max_length=20)
class Dog(Animal):
color = models.CharField(max_length=10)
我有一个名为echo_category的帖子保存回调:
def echo_category(sender, **kwargs):
print "category: '%s'" % kwargs['instance'].category
post_save.connect(echo_category, sender=Dog)
我有这个装置:
[
{
"pk": 1,
"model": "animal.animal",
"fields": {
"category": "omnivore"
}
},
{
"pk": 1,
"model": "animal.dog",
"fields": {
"color": "brown"
}
}
]
在程序的每个部分中,除了在post_save回调中,以下情况都是如此:
from animal.models import Dog
Dog.objects.get(pk=1).category == u'omnivore' # True
当我运行syncdb并安装fixture时,运行echo_category函数。 syncdb的输出是:
$ python manage.py syncdb --noinput
Installing json fixture 'initial_data' from '~/my_proj/animal/fixtures'.
category: ''
Installed 2 object(s) from 1 fixture(s)
这里奇怪的是狗对象的category属性是一个空字符串。为什么它不像其他地方那样“杂食”?
作为临时(希望)解决方法,我在post_save回调中从数据库重新加载对象:
def echo_category(sender, **kwargs):
instance = kwargs['instance']
instance = sender.objects.get(pk=instance.pk)
print "category: '%s'" % instance.category
post_save.connect(echo_category, sender=Dog)
这有效,但它不是我喜欢的东西,因为我必须记住当模型从另一个模型继承并且它必须再次访问数据库时才这样做。另一个奇怪的事情是我必须使用instance.pk来获取主键。普通的'id'属性不起作用(我不能使用instance.id)。我不知道为什么会这样。也许这与category属性没有做正确的事情有关?
答案 0 :(得分:5)
这是因为使用loaddata
/ syncdb
命令从fixture中加载的数据在数据库中保存为 raw :只保存生成的模型表的字段,避免为类层次结构中的所有模型访问数据库。
但是,当模型保存为原始时,您会在信号中获得额外的raw
关键字参数,因此您可以正确处理案例。你的信号会像那样结束:
def echo_category(sender, **kwargs):
if kwargs.get('raw', False):
instance = sender.objects.get(pk=kwargs['instance'].pk)
else:
instance = kwargs['instance']
print "category: '%s'" % instance.category
post_save.connect(echo_category, sender=Dog)
这样,在处理灯具时你只会得到额外的数据库查询(我猜你的情况可以接受)。
关于您的其他问题:
另一个奇怪的是我必须使用instance.pk来获取主键。普通的'id'属性不起作用(我不能使用instance.id)。我不知道为什么会这样。
id
和pk
的语义略有不同。在您的示例中,id
对象的Dog
是AutoField
类中定义的Animal
(automagically)。然而,pk
是OneToOneField
类中的Dog
(再次automagically defined)。
在实践中,两个字段始终具有相同值。但是,由于id
是来自Animal
的字段,因此保存为 raw 的Dog
对象不存在。
希望有所帮助。
编辑:此问题已在django的trac here上报告。