2012-11-27 7 views
12

Ich habe dieses Modell in meinem Code:Wie filtert man das Django-Modell mit seinen Objekten im Viele-zu-Viele-Feld (exakte Übereinstimmung)?

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

und ich brauche diese "Gespräch" Modellobjekte von den "Teilnehmern" many-to-many-Feld zu filtern. Bedeutung: Ich habe zum Beispiel 3 Benutzerobjekte, also möchte ich die einzigen "Conversation" -Objekte abrufen, die diese 3 Benutzer in ihrem "Teilnehmer" -Feld hat.

Ich habe versucht, dies zu tun:

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

wo Sender und ist Objekte eine Liste von User "Empfänger" ist. es wird keinen Fehler auslösen, aber es gibt mir das falsche Objekt der Konversation. Danke.

edit: Ein neueres versuchen, mich dazu führen:

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

, die im Grunde das gleiche Problem haben. Es liefert Objekte, die einen oder mehrere der "Teilnehmer" in der Liste haben. Aber was ich suche, ist die exakte Übereinstimmung des Viele-zu-Viele-Objekts. Bedeutet, ein Objekt mit dem genauen "Benutzer" ist es viele-zu-viele Beziehung.

edit 2: Mein letzter Versuch. immer noch, wird nicht funktionieren.

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

Dies ist auch hier [Frage] (http://stackoverflow.com/questions/13435394/get-instance-by-exact-m2m-values/13435503#13435503) – PepperoniPizza

+0

Die Antwort dort ist unvollständig. Ich muss genau die Benutzer treffen. Das bedeutet, dass Sie ein Conversation-Objekt abrufen, das genau die gewünschten Benutzer enthält, nicht weniger, nicht mehr. – SnirD

Antwort

6

Ok, so fand ich die Antwort: Um eine exakte Übereinstimmung I Kettenfilter das Modell haben zu machen und dann sicherstellen, dass es die genaue Anzahl der Argumente hat es haben muss, so dass die vielen -to-many field hat die Objekte benötigt und nicht mehr.

Ich werde prüfen, für die Objekte Nummer Anmerkung mit: (https://docs.djangoproject.com/en/dev/topics/db/aggregation/)

mit diesem Code endete:

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

Für die schnelle Suche Datenbankindex verwendet wird, verwende ich diesen Code:

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() 

Dies fügt Overhead beim Speichern, aber jetzt kann ich schnell Filter mit diesem Schnipsel durchführen:

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) 
Verwandte Themen