Добавление элемента ко многим ко многим после создания в django - PullRequest
0 голосов
/ 22 марта 2020

Недавно я пытался что-то с этим сделать. Думайте о семье как о группе в Facebook.

class Family(models.Model):
    name = models.CharField(max_length=50)
    owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='owned_families')
    users = models.ManyToManyField(User, related_name='families', blank=True)

давайте предположим, что у нас есть этот семейный объект с именем fm, для иллюстрации.

Моя проблема в том, что owner - это один users верно? Я имею в виду, когда кто-то создает семью, он теперь владелец, верно? он владеет им, но он все еще пользователь, указанный в его списке пользователей. Теперь, когда я создаю новое семейство fm, я хочу добавить fm.owner к fm.users.

Давайте поговорим о том, что я пробовал.

  • post_save сигнал не работает с м2. X

  • m2m_changed происходит, когда поле изменено, но не создано. X

  • Переопределяющий save метод, позвольте мне показать, что я пытался достичь. ?
    def save(self, *args, **kwargs):
        old = self.pk
        super(Family, self).save(*args, **kwargs)

        if old is None:
            print('This actually shows up')
            self.users.add(self.owner)

По сути, это сохраняет ПК каждый раз, когда создается первое семейство, Перед вызовом super..... у него нет .pk так что я рассчитываю на это, чтобы проверить, не было ли у него pk (при создании).

Проблема в self.users.add(self.owner) не работает.

Я пытался клонировать объект в целом и отслеживать его, как

    def save(self, *args, **kwargs):
        old = self
        super(Family, self).save(*args, **kwargs)

        if old is None:
            print("This actually doesn't show up")
            self.users.add(self.owner)

Это на самом деле ужасно, требуется обращение к себе и при вызове super...., self и его ссылка old видоизменяется, я просто хотел показать это, поскольку сам этот вопрос может решить чью-то проблему.

Так что я решил это с помощью.

import copy
    def save(self, *args, **kwargs):
        old = copy.deepcopy(self)
        super(Family, self).save(*args, **kwargs)

        if old is None:
            print('This actually shows up')
            self.users.add(self.owner)

, но self.users.add(self.owner) все еще не работа.

Чего мне не хватает?

1 Ответ

1 голос
/ 22 марта 2020

Проблема, вероятно, в том, что в django admin экземпляр сохраняется первым, и только после сохраняются встроенные наборы форм и m2m-поля. Если владельца там нет, он будет удален. Вы можете переопределить некоторые функции в админке, чтобы исправить это:

class FamilyAdmin(ModelAdmin):
    def save_related(self, request, form, formsets, change):
        super(FamilyAdmin, self).save_related(request, form, formsets, change)
        form.instance.users.add(form.instance.owner)

Кроме того, вы можете попробовать (обратите внимание, что существуют другие способы удалить владельца, который не обнаружен ни одним сигналом или другим хуком) для предотвратить код от удаления владельца:

from django.db.models.signals import m2m_changed
from django.dispatch import receiver

@receiver(m2m_changed, sender=Family.users.through)
def famliy_users_changed(sender, **kwargs):
    family = kwargs['instance']
    pk_set = kwargs['pk_set']
    action = kwargs['action']
    if action == "pre_add":
        pk_set.add(family.owner_id)
    if action == "pre_remove":
        pk_set.remove(family.owner_id)
    if action == "post_clear":
        family.users.add(family.owner)

Но, вообще говоря, вы перепрыгиваете через эти обручи, потому что вы денормализуете свои данные (размещение владельца в пользователях делает эту информацию избыточной, заставляя вас сохранять ваши данные правильными ). Поскольку вы всегда знаете, что владелец является одним из пользователей, почему бы не включить это в метод

class Family(...):
    # ...
    def members(self):
        return User.objects.filter(Q(pk__in=self.users.all()|Q(pk=self.owner_id)))

и получить доступ к членам семьи с помощью этого метода?

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