Ошибка при сохранении модели во второй раз в Django - PullRequest
0 голосов
/ 12 апреля 2020

У меня следующая структура моделей:

class Parent(models.Model):
     fieldA = models.TextField()
     fieldB = models.TextField()

class Child(Parent):
     fieldC = models.CharField()

Я заметил неожиданное поведение в следующем фрагменте кода:

child = Child(fieldA = 'Text fieldA', fieldB = 'Text fieldB', fieldC = 'Text fieldC')
child.full_clean()
child.save()

self.assertEqual(Child.objects.count(), 1)
child.delete()
self.assertEqual(Child.objects.count(), 0)

child.full_clean()
child.save()

Не понимаю, почему я добавляю второе child.save(), утверждения передаются, но когда я хочу сохранить его с этой второй ошибкой, происходит сбой с ValueError:

ValueError: save () запрещен для предотвращения потери данных из-за несохраненного связанного объекта parent_ptr '

В то же время я не вижу такой ошибки со следующим кодом:

parent = Parent(fieldA = 'Text fieldA', fieldB = 'Text fieldB')
parent.full_clean()
parent.save()

self.assertEqual(Parent.objects.count(), 1)
parent.delete()
self.assertEqual(Parent.objects.count(), 0)

parent.full_clean()
parent.save()

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

1 Ответ

2 голосов
/ 13 апреля 2020

Происходит то, что вы пользуетесь функцией, называемой "наследование нескольких таблиц".

https://docs.djangoproject.com/en/3.0/topics/db/models/#multi -table-наследование

Что это Это означает, что вместо Child, представляющего таблицу с тремя полями, он имеет только два поля: fieldC и внешний ключ (OneToOneField) для записи в Parent.

При удалении Child удаляет строки Child и Parent. Когда вы снова попытаетесь сохранить экземпляр Child, значение parent_ptr OneToOneField все еще содержит идентификатор старой строки Parent, которая указывает на то, что больше не существует.

Возможно, вы вместо этого хотите использовать абстрактные базовые классы:

https://docs.djangoproject.com/en/3.0/topics/db/models/#abstract -base-classes

class Base(models.Model):
     fieldA = models.TextField()
     fieldB = models.TextField()
     class Meta:
        abstract = True


class Parent(Base):
    pass

class Child(Base):
     fieldC = models.CharField()

Здесь нет никакой связи между Parent и Child: таблица, которую представляет Child, имеет три поля, а таблица, которую представляет Parent, имеет два поля.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...