2017-06-28 2 views
3

Ich habe diese Modelle und ich muss einige Berechnungen durchführen und sie dem Benutzer präsentieren. Ich rendere ca. 2-3k Zeilen, was zu 4k Anfragen an die DB (angezeigt von Debug-Toolbar) führt. Gibt es eine Möglichkeit, dies zu optimieren? Ich habe mit prefetch_related versucht, aber es kommt noch hinzu, eine weitere Abfrage auf der 4k bereits die getan werden ..Django Queryset-Optimierung: Reverse Lookup auf _set mit Filter

class Cart(models.Model): 
    name = models.CharField(max_length=15) 
    user = models.OneToOneField(User) 


    def sum_for_this(self, taxtype, tax): 
     return self.carttax_set.filter(tax__type__name=taxtype, 
             tax__tax=tax).aggregate(
      sum=Coalesce(Sum('tax_amount'), Value('0')) 
     ).get('sum') 


class TaxType(models.Model): 
    name = models.CharField(max_length=10) 


class Tax(models.Model): 
    name = models.CharField(max_length=100) 
    type = models.ForeignKey(TaxType) 
    tax = models.DecimalField() 


class CartTax(models.Model): 
    cart = models.ForeignKey(Cart) 
    tax = models.ForeignKey(Tax) 
    base = models.IntegerField() 
    tax_amount = models.IntegerField() 

Was ich in Vorlage zu tun ist:

{% for cart in cartlist %} 
{{ cart.sum_for_this }} 
{% endfor %} 

ich mit diesem habe versucht, aber keine Wirkung:

Cart.objects.prefetch_related('carttax_set').all() 

Diese Methode def sum_for_this wird, um alle Anfragen zu tun ..

+2

Sie könnten versuchen, mit [ 'Prefetch'] (https://docs.djangoproject.com/en/1.11/ref/ models/querysets/# django.db.models.Prefetch), um das von Ihnen abgerufene Abfrage-Set zu filtern. Führen Sie dann die Summe in Python aus, anstatt aggregate zu verwenden. – Alasdair

Antwort

3

Versuchen Sie Annotate mit conditional expressions zu verwenden. Ihre Anfrage wird wie folgt aussehen:

from django.db.models import Q, F, Sum, Case, When, IntegerField 
from django.db.models.functions import Coalesce 


cartlist = Cart.objects.annotate(
    sum=Coalesce(Sum(Case(
     When(Q(carttax__tax__type__name=taxtype) & Q(carttax__tax__tax=tax), then=F('carttax__tax_amount')), 
     output_field=IntegerField() 
     )), 0) 
    ) 

Und in Vorlage:

{% for cart in cartlist %} 
{{ cart.sum }} 
{% endfor %} 
+0

Dies wird meine Abfrage eingrenzen .. Ich brauche Daten gefiltert nach Benutzer (meine Frage bearbeitet) und dann versuchen, diese Anmerkungen Koaleszieren oder Aggregieren ... –

+0

Was meinst du? –

+0

Ich muss alle Cart-Objekte, die Benutzer gehören, zurückgeben und dann die Berechnungen durchführen. Dies filtert sie basierend auf carttax_set__tax__type__name afaik –