2016-07-18 6 views
3

Ich schreibe eine Django App für meine Brüderschaft auf Ruschees abstimmen, ich versuche, eine meiner Abfragen zu optimieren, die die Stimmen zählt und die Zählung zusammen mit Informationen aus ihren Anwendungen. Django-Debug-Toolbar ist mir zu sagen, ich habe viele doppelte abfragtDjango Query Optimization zählen ein verwandtes Feld eines verwandten Felds

(der Code unten wurde gekürzt und bearbeitet für Klarheit)

models.py

votechoices = ((1, "Yes"),(2, "No"),(3, "Abstain")) 

class Vote(models.Model): 
     brother = models.ForeignKey(Brother) 
     rushee = models.ForeignKey(Rushee) 
     choice = models.IntegerField(choices=votechoices, default=3) 

class Rushee(models.Model): 
     first_name = models.CharField(max_length=40) 
     last_name = models.CharField(max_length=40) 
     #ETC, ETC 

class Application(models.Model): 
     rushee = models.ForeignKey(Rushee) 
     address = models.CharField(max_length=200) 
     cellphone = models.CharField(max_length=30) 
     #ETC, ETC 

views.py

def getvotecount(request): 

    # get all the applications (we only vote on people who have an application) 
    applicationobjs = Application.objects.select_related('rushee').all() 

    # iterate through the applications and count the votes 
    for app in applicationobjs.iterator(): 

    #>>>> This Query below is a seperate query everytime! So that means that If we have 200 rushees there are 200 queries! 
      counts = Vote.objects.filter(rushee=app.rushee).values('choice').annotate(count=Count('choice')) 

      votesfor = sum([x['count'] for x in counts if x['choice'] == 1]) 
      votesagainst = sum([x['count'] for x in counts if x['choice'] == 2]) 

      result = [app.rushee.first_name + ' ' + app.rushee.last_name, 
        app.address, app.cellphone, 
        str(votesfor), str(votesagainst),] 

    # Uninteresting stuff below that will group together and return the results 

Ich versuche, die Abfrage in der mit (>>>>) markierten Ansicht zu optimieren, so dass ich die Anzahl der Stimmen für jeden Rushee zurückgeben kann, ohne jedes Mal eine separate Abfrage auszuführen!

Zusatzinfo: SQLite-Backend, gibt es viele weitere rushees als es Anwendungen, und wir nur auf den rushees stimmen, die Anwendungen zu tun haben

Antwort

2

Sie conditional expressions dies zu tun, alle in einer Abfrage verwenden können:

from django.db.models import Case, IntegerField, Sum, When 

rushees = Rushee.objects.annotate(
    votes_for=Sum(
     Case(
      When(vote=1, then=1), 
      default=0, 
      output_field=IntegerField(), 
     ) 
    ), 
    votes_against=Sum(
     Case(
      When(vote=2, then=1), 
      default=0, 
      output_field=IntegerField(), 
     ) 
    ) 
) 

die rushees in der resultierenden queryset wird für jeweils eine votes_for und votes_against Eigenschaft mit den Zählungen haben. Dies setzt voraus, dass keine Votings gegen rushees registriert sind, die keine Anwendungen haben - aber wenn es sie gäbe, könnten Sie diese einfach ausfiltern.

+0

Wäre es nicht besser, "Count" anstelle von "Sum" zu verwenden, um zu zählen? Wenn keine Zeilen vorhanden sind, gibt "Count" 0 zurück und "Sum" gibt None zurück. –

+0

Ich folge nicht ... 'Count 'würde eine Zählung aller Zeilen und nicht nur Zeilen zurückgeben, wo der Wert von' vote' dem entspricht, was benötigt wird? – solarissmoke

+0

Ja, tatsächlich ... –

Verwandte Themen