2009-12-24 1 views
6

Diciamo che ho un tale modelloDjango molti segnali simili?

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

Come ti consigliamo di aggiornare il valore USERS_COUNT se Evento aggiungere/eliminare alcuni utenti?

+0

Vedere anche http://stackoverflow.com/questions/13321398/django-manytomanyfield-add-method/26898320#26898320 –

risposta

8

Se possibile nel tuo caso, si potrebbe introdurre Participation modello che si unirebbero evento e utente:

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

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

e la maniglia del segnale inviato dal pre_save Participation per aggiornare instance.event conta. Semplificherebbe significativamente la gestione di m2m. E nella maggior parte dei casi, si scopre in seguito che alcune logiche e dati si adattano meglio al modello centrale. Se non è il tuo caso, prova una soluzione personalizzata (non dovresti avere molti percorsi di codice che aggiungono Utenti agli eventi comunque).

-4

C'è un "design pattern" for that.

Praticamente, ignorare save() e delete().

Come menzionano, l'uso degli ascoltatori è anche un'opzione, ma per questo scenario tendo a preferire il meccanismo di override.

+2

PS. Quel collegamento è per una raccolta davvero utile di meccanismi per realizzare cose usando Django. Non sono davvero modelli di design. Ma il sito è utile in ogni caso. – cethegeek

+6

override save() ed delete() non aiutano con la relazione many-to-many –

2

Ignorare save() potrebbe non essere d'aiuto in quanto l'aggiornamento di M2M non è atomico e succede dopo il salvataggio dell'istanza Event (non ho studiato la semantica delete() ma probabilmente sono simili). Questo è stato discusso in another thread.

Le persone parlano e working on this problem. La soluzione migliore che ho visto finora è this MonkeyPatch by gregoirecachet. Non so se questo diventerà 1,2 o meno. Probabilmente non da quando il Release Manager (James Bennett) sta cercando di convincere la gente a rispettare le date di congelamento (una delle maggiori appena passate).

+0

+1: Non ho nemmeno letto il modello abbastanza vicino per vedere la relazione M2M. E le informazioni su questa risposta sono molto utili. – cethegeek

4

Ho risolto il problema utilizzando il segnale incorporato django.db.models.signals.m2m_changed.

Nel mio caso, devo aggiornare un'istanza correlata di un altro modello ogni volta che ManyToMany cambia e, come sapete, l'override di Model.save() non funziona.

Ecco i miei (francese & semplificati) modelli:

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) 

Forse questa soluzione è tutt'altro che ideale, ma io odio scimmia-patching Django!

+0

Di gran lunga una soluzione molto utile per questa data (Django 1.4). Il segnale m2m_changed collegato al modello passante del campo m2m ha funzionato come un sogno. – garromark