Невозможно загрузить приспособление для сквозной модели django
Что я пытаюсь сделать?
Я создал приспособление для сквозной модели и теперь хочу загрузить его в свою базу данных.
В чем проблема?
При загрузке приспособления с помощью команды Django loaddata
для сквозной модели я получаю эту ошибку:
django.core.serializers.base.DeserializationError: Problem installing fixture
'<fixture-path>/fixtures/m.json': ['“Dave Johnson” value must be an integer.']:
(room.membership:pk=None) field_value was 'Dave Johnson'
models.py
class Person(models.Model):
name = models.CharField(max_length=100, unique=True)
def natural_key(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=100, unique=True)
members = models.ManyToManyField(Person, through='Membership')
def natural_key(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
joined_on = models.DateTimeField(auto_now_add=True)
objects = MembershipManager()
def natural_key(self):
return self.person.name, self.group.name
Я создаю приспособление следующим образом:
python manage.py dumpdata room.Membership --natural-foreign --natural-primary > m.json
что создает следующий json:
[
{
"model": "room.membership",
"fields": {
"person": "Dave Johnson",
"group": "Django Learning",
"joined_on": "2020-12-03T13:14:28.572Z"
}
}
]
Я также добавил get_by_natural_key
метод в менеджере для сквозной модели следующим образом:
class MembershipManager(models.Manager):
def get_by_natural_key(self, person_name, group_name):
return self.get(person__name=person_name, group__name=group_name)
И загрузка приспособления
python manage.py loaddata m.json
Другие модели работают нормально. Я могу загрузить их без каких-либо проблем, только сквозная модель не работает.
Вы создаете модель, а не менеджер. Вы также должны убедиться, что комбинация полей уникальна:
class MembershipManager(models.Manager):
def get_by_natural_key(self, person_name, group_name):
return self.get(person__name=person_name, group__name=group_name)
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
joined_on = models.DateTimeField(auto_now_add=True)
objects = MembershipManager()
class Meta:
constraints = [
models.UniqueConstraint(
fields=['person', 'contact'], name='unique_person_group'
)
]
def natural_key(self):
return self.person.name, self.group.name
Для моделей Person
и Group
вам также понадобятся менеджеры:
class NameManager(models.Manager):
def get_by_natural_key(self, name):
return self.get(name=name)
class Person(models.Model):
name = models.CharField(max_length=100, unique=True)
objects = NameManager()
def natural_key(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=100, unique=True)
members = models.ManyToManyField(Person, through='Membership')
objects = NameManager()
def natural_key(self):
return self.name
После более детального изучения исходного кода django о команде loaddata
я обнаружил, что она использует внутреннюю десериализацию django. Поэтому я решил почитать о сериализации и десериализации, где есть это раздел в документации, который говорит о зависимостях во время сериализации.
Исходя из этого, следующие изменения устранили проблему:
Решение:
Обновите сквозной метод модели natural_key
и добавьте natural_key
зависимости:
def natural_key(self):
return self.person.natural_key(), self.group.natural_key()
natural_key.dependencies = ['room.Person', 'room.Group']
Я также обновил natural_key
обеих моделей Person
и Group
, чтобы возвращать кортеж, а не один элемент, т.е. return self.name,
. Кроме того, я добавил менеджеры для обеих моделей.