Джанго много-много сигналов?

допустим у меня такая модель

class Event(models.Model)
    users_count = models.IntegerField(default=0)
    users = models.ManyToManyField(User)

Как бы вы порекомендовали обновить значение users_count, если событие добавляет/удаляет некоторых пользователей?


person Pydev UA    schedule 24.12.2009    source источник


Ответы (4)


Если возможно в вашем случае, вы можете ввести модель Participation, которая объединит событие и пользователя:

class Participation(models.Model):
    user = models.ForeignKey(User)
    event = models.ForeignKey(Event)

class Event(models.Model):
    users = models.ManyToManyField(User, through='Participation')

И обработайте сигнал pre_save, отправленный Participation для обновления instance.event счетчиков. Это значительно упростило бы работу с m2m. И в большинстве случаев позже выясняется, что некоторая логика и данные лучше всего подходят для средней модели. Если это не ваш случай, попробуйте специальное решение (в любом случае у вас не должно быть много путей кода, добавляющих пользователей к событиям).

person kibitzer    schedule 24.12.2009

Я исправил проблему, используя встроенный сигнал django.db.models.signals.m2m_changed.

В моем случае мне приходится обновлять связанный экземпляр другой модели каждый раз, когда изменяется ManyToMany, и, как вы знаете, переопределение Model.save() не работает.

Вот мои (французские и упрощенные) модели:

class BaseSupport(EuidModel):
    nom = models.CharField(max_length=100, blank=True)
    periodicite = models.CharField('périodicité', max_length=16,
                                   choices=PERIODICITE_CHOICES)
    jours_de_parution_semaine = models.ManyToManyField('JourDeLaSemaine', blank=True)

    class Meta:
        abstract = True


class Support(BaseSupport):
    pass

    def save(self, *args, **kwargs):
        create_cahier_principal = False
        if not self.pk:
            create_cahier_principal = True
        super(Support, self).save(*args, **kwargs) 
        if create_cahier_principal:
            c = Cahier.objects.create(support=self,ordre=1, numero=1,
                                      nom=self.nom, nom_court=self.nom_court,
                                      euid=self.euid, periodicite=self.periodicite)



class Cahier(BaseSupport):
    """Ex : Cahier Saumon du Figaro Quotidien."""
    support = models.ForeignKey('Support', related_name='cahiers')
    ordre = models.PositiveSmallIntegerField()
    numero = models.PositiveSmallIntegerField(u'numéro', null=True, blank=True)


def sync_m2m_cahier_principal(sender, **kwargs):
    if kwargs['action'] not in ('post_add', 'post_clear', 'post_remove'):
        return
    support = kwargs['instance']
    cahier_principal = support.cahiers.get(euid=support.euid)
    cahier_principal.jours_de_parution_semaine.clear()
    if kwargs['action'] == 'post_clear':
        return 
    for jour in support.jours_de_parution_semaine.all():
        cahier_principal.jours_de_parution_semaine.add(jour)
m2m_changed.connect(sync_m2m_cahier_principal,
                    sender=Support.jours_de_parution_semaine.through)

Возможно, это решение далеко от идеального, но я ненавижу патчить Django!

person Stan    schedule 18.05.2011

Переопределение save() может вам не помочь, потому что обновление M2M не является атомарным и происходит после сохранения экземпляра Event (я не изучал семантику delete(), но они, вероятно, похожи) . Это обсуждалось в другой теме.

Люди обсуждают и работают над этой проблемой. Лучшее решение, которое я видел до сих пор, — это это MonkeyPatch от gregoirecachet. Я не знаю, войдет ли это в 1.2 или нет. Вероятно, нет, поскольку менеджер по выпуску (Джеймс Беннетт) пытается заставить людей соблюдать даты заморозки (только что прошла важная дата).

person Peter Rowell    schedule 24.12.2009

Для этого существует "шаблон проектирования".

Практически переопределить save() и delete().

Как они упоминают, использование слушателей также является вариантом, но для этого сценария мне больше нравится механизм переопределения.

person cethegeek    schedule 24.12.2009
comment
PS. Эта ссылка предназначена для действительно полезной коллекции механизмов для выполнения задач с использованием Django. На самом деле они не являются шаблонами проектирования. Но тем не менее сайт полезный. - person cethegeek; 24.12.2009
comment
переопределение save() и delete() не поможет с отношениями "многие ко многим" - person Pydev UA; 25.12.2009