2017-11-24 1 views
0

Lassen Sie uns sagen, ich habe eine einfache Abstimmungsform mit verschiedenen Antworten. können die Leute mehrfach von einer IP abstimmen. Ich kann leicht finden, wie viele Stimmen eine gegebene Antwort bekommen hat - a.vote_set.all().count() (keine Begrenzung der Stimmen von 1 IP) Ich kann auch herausfinden, wie viele Stimmen es gab, angesichts der Grenze 1 Stimme von 1 IP - a.vote_set.all().values('ip').distinct().count() (Grenze der Stimmen von eins IP = 1) Wie bekomme ich die Summe der Stimmen für eine gegebene Antwort, vorausgesetzt ich möchte bis zu 10 Stimmen von 1 IP zählen (Limit = 10)?Django Abfrage - zählen Sie bis zu 10 Stimmen aus einer IP

Um meine Frage zu klären: Ich brauche eine Django orm Abfrage, um alle Stimmen für eine gegebene Antwort zu bekommen - aber mit dieser Bedingung, dass ich bis zu 10 Stimmen von einer IP zählen will. Beispiel: Antwort A hat insgesamt 100 Stimmen erhalten. Die 100 Stimmen aus der folgenden IP kam (entweder eine Person gewählt oder ein Paar von ihnen, die gemeinsame öffentliche IP gemeinsam):

1) 120.xxx - 20 Stimmen 2) 121.xxx - 50 Stimmen 3) 122. xxx - 10 Stimmen 4) 123.xxx - 5 Stimmen 5) 124.xxx - 15 Stimmen

ich die Abfrage will 45 Stimmen zurückzukehren: 10 Stimmen von IP 1) (10, nicht 20, weil 10 ist eine Grenze), 10 von 2), 10 von 3), 5 von 4) und schließlich 10 von 5.

Ich weiß nicht im Voraus, wie viele IPs die Wähler verwendet haben. Bitte sagen Sie mir nicht, dass dieser Anwendungsfall unwahrscheinlich ist - es ist real, ich muss es tun und stecken geblieben: P

Antwort

1

In Ordnung, dies ist keine kurze Antwort, aber ich habe dies in der Django-Shell verifiziert und von den wenigen Tests, die ich ausgeführt habe, scheint es korrekt zu zählen.

Ich nehme an, Sie haben ein Modell, das auf diese vereinfacht werden kann:

class Answer(models.Model): 
    answertext = models.CharField(max_length=200) 

class Vote(models.Model): 
    answer = models.ForeignKey(Answer, on_delete=None) 
    ip = models.CharField(max_length=15) 

Wenn ich Ihre Frage richtig verstanden habe, wollen wir nun die Anzahl der Stimmen für eine Antwort zählen - Begrenzung der Anzahl der mal eine einzelne IP kann bis 10 stimmen.

Ich werde die verschiedenen Komponenten zerlegen und am Ende die komplette Aussage geben.

Zuerst filtern wir eine bestimmte Antwort heraus. Sie wollen wahrscheinlich etwas Bestimmtes hier - ich habe nur alle "Ja" Antworten genommen. Wir beschriften mit dem Grafen so erhalten wir die alle Ja Antworten aufgelistet den Abstimmungs IPs und die Anzahl der diese IPs abgestimmt:

Vote.objects.filter(answer__answertext='Yes').values('ip').annotate(ipcount=Count('id')) 

Als nächstes werden wir alle IPs mit einer Zählung von mehr als 10 bis maximal begrenzen müssen von 10 Stimmen. Wir machen das mit den Case- und When-Ausdrücken. Im Grunde sagt das, geben Sie uns ein neues Feld, das der Stimmenzählung von einer IP entspricht, wenn die Anzahl kleiner oder gleich 10 ist, und begrenzen Sie das neue Feld auf 10, wenn die IP-Stimmenzahl größer als 10 ist.

.annotate(limitedipcount = Case(
    When(ipcount__lte=10, then='ipcount'), 
    When(ipcount__gt=10, then=10), 
    output_field=IntegerField()) 
) 

Schließlich müssen wir diese neue ‚limitedipcount‘ zusammenzufassen und wir tun dies mit einem einfachen Aggregatausdruck:

.aggregate(totallimitedipcount=Sum('limitedipcount')) 

Wenn Sie all das zusammen Sie so etwas wie dieses:

Vote.objects.filter(answer__answertext='Yes') 
    .values('ip') 
    .annotate(ipcount=Count('id')) 
    .annotate(limitedipcount = Case(
     When(ipcount__lte=10, then='ipcount'), 
     When(ipcount__gt=10, then=10), 
     output_field=IntegerField()) 
    ) 
    .aggregate(totallimitedipcount=Sum('limitedipcount')) 
0

Ok, so schrieb ich eine Hilfsfunktion mit einem Limit als Parameter (Standard ist keine), die das Wörterbuch erstellt {ip1: num_of_votes1, ip2: num_of_votes2}. Um dieses Wörterbuch zu erstellen, durchläuft die Funktion alle Stimmen für die gegebene Antwort und überprüft jedes Mal die IP einer Abstimmung, wobei sie entscheidet, ob die IP bereits im Wörterbuch ist und ob das Limit für eine gegebene IP erreicht wurde und wenn nicht - Erweiternswert für einen gegebenen Schlüssel. Am Ende summiere ich die Werte - sum(my_dict.values()) und gebe es zurück.

Dies ist wahrscheinlich eine sehr brutale Lösung, also wenn jemand etwas besser weiß, bitte posten Sie es.

+0

Meine Lösung sollte es tun und es ist django-y auch :) –

Verwandte Themen