#django #django-models
#django #django-модели
Вопрос:
У меня есть модель с 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
), с точно такой же процедурой.
Комментарии:
1. Вы пробовали сохранять
pp2
перед его назначением? В документах говорится: «Обратите внимание, что вы должны сохранить объект, прежде чем ему можно будет назначить отношение внешнего ключа»..2. Вероятно, это все. Не стесняйтесь оставить это в качестве ответа, чтобы я мог проверить это, когда попробую позже.
Ответ №1:
Перед назначением объекта в качестве внешнего ключа он должен быть сохранен в базе данных.
В документах Django указано, что «вы должны сохранить объект, прежде чем ему можно будет назначить отношение внешнего ключа».
Это неточно, поскольку Django не запрещает вам назначать несохраненный объект (начиная с версии v2.1). Но если вы сделаете это, родительскому объекту будет присвоено значение null
при сохранении дочернего объекта. Это происходит, даже если вы тем временем сохранили назначенный родительский объект. Что особенно коварно, так это то, что при проверке родительского объекта дочернего объекта ( related_object.parent
) перед сохранением дочернего объекта возвращается допустимый объект (даже с pk
, если родительский объект был сохранен за это время). Внешний ключ устанавливается в None
значение только при попытке сохранения.
Если у вас есть ненулевое ограничение на внешний ключ, вы, по крайней мере, получите сообщение об ошибке при сохранении. Но если у вас нет этого ограничения, вы никогда не узнаете, поскольку 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()
Комментарии:
1. Я прочитал это в документах, причина, по которой я пропустил это, заключается в том, что в другой ситуации я получил сообщение об ошибке, когда я делал подобные вещи. Странно, что меня здесь не предупредили, но спасибо за ответ!
2. Кажется, что оно предупреждает только при использовании
create()
, а неsave()
. Вероятно, не предполагаемое поведение.