Blomqma
Blomqma

Reputation: 23

How do I reduce the amount of queries of my Django app?

My app is currently making over 1000 SQL queries and taking around 20s to load the page. I can't seem to find a way to come up with a solution to get the same data displayed on a table in my template faster. I wan't to display 100 results so that's way my pagination is set to 100.

These are the methods in my my models.py used to get the count and sum of the orders, these two are in my Company model and the get_order_count is also in my Contact model

def get_order_count(self):
    orders = 0
    for order in self.orders.all():
        orders += 1
    return orders

def get_order_sum(self):
    total_sum = 0
    for contact in self.contacts.all():
        for order in contact.orders.all():
            total_sum += order.total
    return total_sum

views.py

class IndexView(ListView):
    template_name = "mailer/index.html"
    model = Company
    paginate_by = 100

template

{% for company in company_list %}
    <tr id="company-row">
        <th id="company-name" scope="row">{{ company.name }}</th>
        <td>{{ company.get_order_count }}</td>
        <td id="order-sum">{{ company.get_order_sum|floatformat:2 }}</td>
        <td class="text-center">
           <input type="checkbox" name="select{{company.pk}}" id="">
       </td>
    </tr>
    {% for contact in company.contacts.all %}
        <tr id="contact-row">
            <th scope="row">&nbsp;</th>
            <td>{{ contact.first_name }} {{ contact.last_name }}</td>
            <td id="contact-orders">
                Orders: {{ contact.get_order_count }} 
            </td>
            <td></td>
        </tr>
    {% endfor %}
{% endfor %}

Upvotes: 0

Views: 105

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599470

Your two methods are very inefficient. You can replace them with annotations which calculate everything in one query in the database. You haven't shown your models, but it would be something like:

class IndexView(ListView):
    template_name = "mailer/index.html"
    model = Company.objects.annotate(order_count=Count('orders')).annotate(order_sum=Sum('contacts__orders__total'))
    paginate_by = 100

Now you can access {{ company.order_count }} and {{ company.order_sum }}.

Upvotes: 8

Related Questions