Djangoで注文のサマリをリスト化して表示したいが、SQLのクエリが多いため、表示するための時間がかかる。
クエリを最適化する方法を知りたい。
class Company(models.Model): name = models.CharField(max_length=150) 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 class Contact(models.Model): company = models.ForeignKey( Company, related_name="contacts", on_delete=models.PROTECT) first_name = models.CharField(max_length=150) last_name = models.CharField(max_length=150, blank=True) def get_order_count(self): orders = 0 for order in self.orders.all(): orders += 1 return orders class Order(models.Model): order_number = models.CharField(max_length=150) company = models.ForeignKey(Company, related_name="orders") contact = models.ForeignKey(Contact, related_name="orders") total = models.DecimalField(max_digits=18, decimal_places=9) order_date = models.DateTimeField(null=True, blank=True) def __str__(self): return "%s" % self.order_number
class IndexView(ListView): template_name = "index.html" model = Company paginate_by = 50
<body> <div style="width:1020px; margin: 0 auto; border:1px solid blue;"> <table width="1020"> {% if is_paginated %} <tr><td> {% if page_obj.has_previous %} <a href="?page={{ page_obj.previous_page_number }}" class="pager-prev{% if not page_obj.has_previous %} inactive{% endif %}">«</a> {% endif %} </td> <td></td> <td></td> <td> {% if page_obj.has_next %} <a href="?page={{ page_obj.next_page_number }}" class="pager-next{% if not page_obj.has_next %} inactive{% endif %}">»</a> {% endif %} </td> </tr> {% endif %} <tr> <th>Name</th> <th>Order Count</th> <th>Order Sum</th> <th>Select</th> </tr> {% for company in company_list %} <tr> <td>{{ company.name }}</td> <td>{{ company.get_order_count }}</td> <td>{{ company.get_order_sum|floatformat:2 }}</td> <td><input type="checkbox" name="select{{company.pk}}" id=""></td> </tr> {% for contact in company.contacts.all %} <tr> <td> </td> <td>{{ contact.first_name }} {{ contact.last_name }}</td> <td>Orders: {{ contact.get_order_count }}</td> <td></td> </tr> {% endfor %} {% endfor %} </table> </div> </body>
期待する表示
|Name|Order Count|Order Sum|Select|
|:--|:--:|--:|
|CompanyA|8|2000|□
||PersonB|Orders: 2|
||PersonC|Orders: 5|
||PersonD|Orders: 1|
|CompanyB|9|1500|□
||PersonD|Orders: 3|
||PersonE|Orders: 1|
||PersonF|Orders: 5|
|CompanyC|15|3500|□
||PersonG|Orders: 10|
||PersonH|Orders: 2|
||PersonI|Orders: 3|
期待する表示通りにできてはいるが、SQL Queryが多すぎるため、表示までに時間がかかる。これを最適化して、高速化したい。
queryset = model.objects.annotateを使って、クエリを最適化し、htmlの記述を変えると良さそうだが、どう最適化したら良いかが分からない。
あなたの回答
tips
プレビュー