Django 2.2.1: изменение отношения OneToOneField - PullRequest
2 голосов
/ 04 июня 2019

В Django 2.2.1 у меня есть две модели, связанные через OneToOneField:

class Woman(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name

class Man(models.Model):
    name = models.CharField(max_length=100)
    wife = models.OneToOneField(
        Woman,
        related_name = 'husband',
        null=True,
        blank=True,
        on_delete=models.SET_NULL
    )

    def __str__(self):
        return self.name

(гетеронормативно для простоты.) Но, как мы все знаем, браки терпят неудачу.Тем не менее, я ужасно изменяю отношения:

>>> john = Man.objects.create(name='John')
>>> alice = Woman.objects.create(name='Alice')
>>> susan = Woman.objects.create(name='Susan')
>>> john.wife = alice
>>> alice.husband
<Man: John>
# After the divorce...
>>> john.wife = susan
>>> susan.husband
<Man: John>
>>> alice.husband
<Man: John>
>>> susan.save()

Traceback (most recent call last):
...
django.db.utils.IntegrityError: UNIQUE constraint failed: appname_woman.husband_id

Хорошо, это имеет смысл: два объекта Woman не могут иметь одного мужа (по крайней мере, в соответствии с действующим законодательством США).Нет проблем;Что делать, если я удаляю оригинальную жену из отношений?

>>> alice.husband = None
>>> alice.save()
>>> alice.husband # None
>>> susan.husband
<Man: John>
# Oh good, no errors. And John is now married to Susan... right? Wrong.
>>> john.save()

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/project/venv/lib/python3.7/site-packages/django/db/models/fields/related_descriptors.py", line 415, in __get__
    self.related.get_accessor_name()
appname.models.Man.wife.RelatedObjectDoesNotExist: Man has no wife.

Похоже, что единственный способ сделать это - это развестись с Джоном до того, как он вступит в повторный брак:

# Starting with a clean database
>>> john = Man.objects.create(name='John')
>>> alice = Woman.objects.create(name='Alice')
>>> susan = Woman.objects.create(name='Susan')
>>> john.wife = alice
>>> alice.husband
<Man: John>
# The marriage was brief...
>>> john.wife = None
>>> john.save()
>>> john.wife = susan
>>> john.save()
>>> susan.save()
>>> alice.save()
# Everybody's happy, we hope.

Какой беспорядок!Теперь вот мой вопрос: как я могу написать код, чтобы гарантировать, что каждый раз, когда объекты Man присваиваются новой Man.wife, предыдущая Man.wife удаляется и проверка проходит успешно?

Ответы [ 2 ]

0 голосов
/ 04 июня 2019

Я думаю, вы делаете это намного сложнее, чем нужно.Вы просто не сохранили john после его изменения.

Это будет работать:

>>> john = Man.objects.create(name='John')
>>> alice = Woman.objects.create(name='Alice')
>>> susan = Woman.objects.create(name='Susan')
>>> john.wife = alice
>>> john.save()
>>> john.wife = susan
>>> john.save()
0 голосов
/ 04 июня 2019

попробуйте эту функцию,

from django.core.exceptions import ObjectDoesNotExist


def marriage(man_name, women_instance):
    try:
        women_instance.husband = None
        women_instance.save()
        return Man.objects.create(name=man_name, wife=women_instance)
    except ObjectDoesNotExist:
        return Man.objects.create(name=man_name, wife=women_instance)

Использование

women_instance = Woman.objects.get(name="bar")
man_name = "Foo"
man_instance = marriage(man_name, women_instance)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...