I'm having problems with the performance of Django query. Assume I have 3 models and I have 100 rows in Company table:
from django.db import models
class Company(models.Model):
name = models.CharField()
def order_count(self):
return self.orders.count()
def order_sum(self):
return (self.orders.all().aggregate(models.Sum('total')))['total__sum']
class Customer(models.Model):
company = models.ForeignKey(Company, related_name="customer", on_delete=models.PROTECT)
name = models.CharField()
def order_count(self):
return self.orders.count()
class Order(models.Model):
company = models.ForeignKey(Company, related_name='orders')
customer = models.ForeignKey(Customer, related_name="orders")
value = models.FloatField()
I want my template to show company's name and sum of its orders, then for each customer of this company, I want to show the customer name with the number of their orders. My query code in views.py
is using prefetch like this:
queryset = Company.objects.prefetch_related(
models.Prefetch('customer',
queryset=Customer.objects.prefetch_related('orders')), 'orders')
My pseudocode for template
:
for company in queryset:
print(company.name, company.order_count, company.order_sum)
for customer in company:
print(customer.name, customer.order_count)
I've checked with Django Debug Toolbar, it takes 105 queries, with these SQL sentence (pseudo code):
SELECT * FROM company
SELECT * FROM customer WHERE customer.company_id IN (100 IDs of the companies)
SELECT * FROM order WHERE order.customer_id IN (the IDs from previous command)(this duplicates 2 times)
SELECT * FROM order WHERE order.company_id IN (100 IDs of the companies)
SELECT SUM(order.value) FROM order WHERE order.company_id = %s (this duplicates 100 times, for each company's id)
As Django Debug Toolbar (DjDT) shows me:
So my questions are:
You could use annotate function to get order sum in a single query. For example
queryset = Company.objects.annotate(
order_sum=Sum("orders__value")
).prefetch_related(
models.Prefetch('customer', queryset=Customer.objects.prefetch_related('orders')), 'orders'
)
Then you can access order_sum value like others attribute, using dot operator
for company in queryset:
print(company.order_sum)
You can read the Django docs for more understanding
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.