Django不会保存保存前分配的OneToOne关系

时间:2019-03-26 11:24:01

标签: django django-models

我有一个模型,其自身具有一个OneToOne字段:

class Préinscription(models.Model):
    plus_un = models.OneToOneField('self', on_delete=models.SET_NULL,
        null=True, default=None, related_name='+')

当我尝试在实例上设置此字段时,它不起作用。

在下面的代码中,pppp2Pré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)进行操作时,它却完全相同。

1 个答案:

答案 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()