2012-11-27 8 views
12

Ho questo modello nel mio codice:Come filtrare il modello django con i suoi oggetti nel campo molti-a-molti (corrispondenza esatta)?

class Conversation(models.Model): 
    participants = models.ManyToManyField(User, related_name="message_participants") 

e ho bisogno di filtrare questa "conversazione" oggetti del modello dai molti-a-molti campo "partecipanti". significato: ho per esempio 3 oggetti utente, quindi voglio recuperare gli unici oggetti "Conversazione" che ha questo 3 utenti nel suo campo "partecipanti".

Ho provato a fare questo:

def get_exist_conv_or_none(sender,recipients): 
    conv = Conversation.objects.filter(participants=sender) 
    for rec in recipients: 
     conv = conv.filter(participants=rec) 

in cui il mittente è un oggetto d'uso e "destinatari" è un elenco di oggetti Utente. non solleverà l'errore ma mi darà l'oggetto di conversazione sbagliato. Grazie.

edit: Una più recente provare mi ha portato a questo:

def get_exist_conv_or_none(sender,recipients): 
    participants=recipients 
    participants.append(sender) 
    conv = Conversation.objects.filter(participants__in=participants) 
    return conv 

che hanno sostanzialmente lo stesso problema. Produce oggetti che ha uno o più "partecipanti" nella lista. ma quello che sto cercando è la corrispondenza esatta dell'oggetto molti-a-molti. Significato, un oggetto con gli "utenti" esatti sulla sua relazione molti-a-molti.

modifica 2: Il mio ultimo tentativo. ancora, non funzionerà.

def get_exist_conv_or_none(sender,recipients): 
    recipients.append(sender) 
    recipients = list(set(recipients)) 
    conv = Conversation.objects.annotate(count=Count('participants')).filter(participants=recipients[0]) 
    for participant in recipients[1:]: 
     conv.filter(participants=participant) 
    conv.filter(count=len(recipients)) 
    return conv 
+1

questo è anche qui [domanda] (http://stackoverflow.com/questions/13435394/get-instance-by-exact-m2m-values/13435503#13435503) – PepperoniPizza

+0

La risposta è incompleta. Devo abbinare esattamente gli utenti. significato recuperare un oggetto di conversazione che ha gli utenti che voglio in esso molti-a-molti esattamente, non meno, non di più. – SnirD

risposta

6

Ok così ho trovato la risposta: Al fine di rendere una corrispondenza esatta devo catena di filtro del modello e quindi assicurarsi che ha il numero esatto di argomenti che deve avere, in modo che i tanti -a-molti campo avrà in esso tutti gli gli oggetti necessari e non di più.

controllerò per il numero di oggetti utilizzando l'annotazione: (https://docs.djangoproject.com/en/dev/topics/db/aggregation/)

finito con questo codice:

def get_exist_conv_or_none(recipients): 
    conv = Conversation.objects.annotate(count=Count('participants')).filter(participants=recipients[0]) 
    for participant in recipients[1:]: 
     conv = conv.filter(participants=participant) 
    conv = conv.filter(count=len(recipients)) 
    return conv 
2

Per una ricerca rapida utilizzando l'indice di database, io uso questo codice:

class YandexWordstatQueue(models.Model): 
    regions = models.ManyToManyField(YandexRegion) 
    regions_cached = models.CharField(max_length=10000, editable=False, db_index=True) 
    phrase = models.ForeignKey(SearchPhrase, db_index=True) 
    tstamp = models.DateTimeField(auto_now_add=True) 

class YandexWordstatRecord(models.Model): 
    regions = models.ManyToManyField(YandexRegion) 
    regions_cached = models.CharField(max_length=10000, editable=False, db_index=True) 
    phrase = models.ForeignKey(SearchPhrase, db_index=True) 
    Shows = models.IntegerField() 
    date = models.DateField(auto_now_add=True) 

@receiver(m2m_changed, sender=YandexWordstatRecord.regions.through) 
@receiver(m2m_changed, sender=YandexWordstatQueue.regions.through) 
def yandexwordstat_regions_changed(sender, **kwargs): 
    if kwargs.get('action') in ['post_add', 'post_remove']: 
     instance = kwargs.get('instance') 
     l = list(instance.regions.values_list('RegionID', flat=True)) 
     l.sort() 
     instance.regions_cached = json.dumps(l) 
     instance.save() 

Questo aggiunge un sovraccarico al salvataggio, ma ora posso eseguire un filtro veloce con questo frammento:

region_ids = [1, 2, 3] # or list(some_queryset.values_list(...)) 
region_ids.sort() 
regions_cahed = json.dumps(region_ids) 
YandexWordstatQueue.objects.filter(regions_cached=regions_cached) 
Problemi correlati