Save() сохраняет все поля, кроме поля ManyToMany
У меня есть модель "Contest" с одним полем m2m под названием "teams", которое связано с моделью "Team".
Я переопределил метод save. В моей функции save() (та, которая переопределяется) мне нужен queryset (в моей переопределяющей функции save) со всеми объектами, связанными с моим m2m-полем team. Код self.teams.all()
, но он не работает, потому что мои модели еще не зарегистрированы в базе данных, правильно? Итак, я вызываю super().save(*args, **kwargs)
теперь мои модели сохранены и я могу получить свой набор запросов?
Я не могу. Кверисет пуст, даже если я зарегистрировал команду(ы). <QuerySet []>
Почему super.save()
сразу сохраняет все поля, кроме m2m ?
Для создания моделей я использую исключительно админку django. Никакой оболочки manage.py или form.
Моя модель :
class Contest(models.Model):
name = models.CharField(max_length=16, primary_key=True, unique=True, default="InactiveContest", blank=True) # Ex: PSGvMNC_09/2017
id = models.IntegerField(default=1)
teams = models.ManyToManyField(Team, verbose_name="opposants")
date = models.DateTimeField(blank=True)
winner = models.ForeignKey(Team, verbose_name='gagnant', related_name='winner', on_delete=models.SET_NULL, blank=True, null=True)
loser = models.ForeignKey(Team, verbose_name='perdant', related_name='loser', on_delete=models.SET_NULL, blank=True, null=True)
bet = models.IntegerField(verbose_name='Nombre de paris', default=0, blank=True, null=0)
active = models.BooleanField(default=False)
def save(self, *args, **kwargs):
if self._state.adding:
self.active = False
# Django's id field immitation
last_id = Contest.objects.all().aggregate(Max('id')).get('id__max')
if last_id is not None:
self.id = last_id + 1
super().save(*args, **kwargs)
print(Contest.objects.get(id=self.id)) # Works --> model saved in db... in theory
queryset = self.teams.all() # Empty all the time !
После того, как save() (переопределяющий) был выполнен один раз, проблема решена и в следующие разы (модификации) я могу получить свой queryset, поэтому я мог бы просто использовать self._state.adding
, но этот метод обязывает меня сохранять 2 раза (создание, редактирование).
Мне нужно понять, почему super().save(*args, **kwargs)
ведет себя так и как я могу решить эту проблему?
Причина в том, что реализация ManyToManyField
не использует таблицу базы данных модели. Она использует третью таблицу для связи между двумя моделями.
Каждая модель имеет свою собственную таблицу базы данных. В вашем примере
model Contest -> table app_contest
model Team -> table app_team
Однако, app_contest
не содержит поля teams
. А app_team
не содержит поля contest
.
Вместо этого существует третья таблица, например, app_contest_team
, которая состоит из трех столбцов:
- id
- contest_id
- team_id
И хранит пары contest_id
+ team_id
, которые представляют связь между конкурсами и командами.
Так что queryset = self.teams.all()
равно SQL выражению:
SELECT * FROM app_teams WHERE id in
(SELECT team_id from app_contest_teams WHERE contest_id = '{self.id}');
Таким образом, видно, что вы не можете каким-либо образом манипулировать ManyToManyField
без наличия экземпляра, первоначально сохраненного в базе данных. Потому что только после вставки в таблицу app_contest
он получает уникальный ID, который в дальнейшем может быть использован для создания записей в третьей таблице app_contest_teams
.
А также из-за этого - save()
не требуется при добавлении нового объекта в ManyToManyField
, потому что таблица модели не затрагивается