我有一个模型,其自身具有一个OneToOne
字段:
class Préinscription(models.Model):
plus_un = models.OneToOneField('self', on_delete=models.SET_NULL,
null=True, default=None, related_name='+')
当我尝试在实例上设置此字段时,它不起作用。
在下面的代码中,pp
和pp2
是Préinscription
的两个实例。
if d['plus_un']:
pp2.nom = d['nom2']
pp2.prénom = d['prénom2']
pp2.mél = d['mél2']
pp.plus_un = pp2
pp2.save()
print(pp2) # First print
p.nb_billets = 2
else:
pp.plus_un = None
if pp2.id:
pp2.delete()
p.nb_billets = 1
p.save()
print(pp2) # Second print
print(pp.plus_un) # Third print
pp.save()
print(pp.plus_un) # Final print
此代码没有错误。但是,这是照片返回的顺序:
Préinscription object (325)
Préinscription object (325)
Préinscription object (325)
None
这意味着即使相关对象已创建且全部创建,也不会保存。
如您所见,我怀疑这可能是由于导致父母或孩子的.plus_un
之间存在冲突,因此我设置了related_name='+'
来避免这种情况。不过,它并没有改变任何东西,无论哪种情况,在迁移后结果都是完全相同的。
请注意,但是当我通过CLI(./manage.py shell
)进行操作时,它却完全相同。
答案 0 :(得分:1)
在将对象分配为外键之前,必须将其 保存到数据库中。
Django docs指出“必须先保存对象,然后才能将其分配给外键关系”。
这是不准确的,因为Django不会阻止您分配未保存的对象(从v2.1开始)。但是,如果执行此操作,则在保存子对象时会将父对象设置为null
。即使您同时保存了分配的父对象,也会发生 。特别隐蔽的是,在保存子对象之前检查子对象(related_object.parent
)的父对象时,将返回有效对象(如果同时保存了父对象,则返回pk
) 。尝试保存时,仅将外键设置为None
。
如果您对外键具有非null约束,则保存时至少会收到错误。但是,如果您没有该约束,您将永远不会知道,因为Django会在保留两个对象而不会抱怨的情况下静默丢弃分配的父对象。例外是使用create()
时;然后,Django在访问数据库之前抛出ValueError
。
所以请务必先保存然后再分配。
# With create(), the object created is immediately saved to the database.
# If you try to save a related_object with an unsaved parent, you get a
# ValueError.
parent_object = Parent.objects.create(field1=value1, field2=value2)
related_object = Related.objects.create(field3=value3, parent=parent_object)
# Alterative with explicit saving
parent_object = Parent(field1=value1, field2=value2)
related_object = Related(field3=value3)
# First save, then assign – the assignment fails silently if
# you do it the other way around.
parent_object.save()
related_object.parent = parent_object
related_object.save()