I am trying to solve performance issues at a Django-based web site, with very little knowledge of Django and Python syntax. I seem to have correctly identified the problem. I also seem to know what to do next, but I can't get a grasp on the Python/Django syntax to make everything work.
class Company(models.Model):
name = models.CharField(max_length=100)
bic = models.CharField(max_length=100, blank=True)
def get_order_count(self):
return self.orders.count()
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.DO_NOTHING)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100, blank=True)
def get_order_count(self):
return self.orders.count()
class Order(models.Model):
order_number = models.CharField(max_length=100)
company = models.ForeignKey(Company, related_name="orders", on_delete=models.DO_NOTHING)
contact = models.ForeignKey(Contact, related_name="orders", on_delete=models.DO_NOTHING)
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
My hunch is that the performance problems are caused by the nested loop in get_order_sum. And my solution is quite clear: nested "fors" should be replaced by a simple command, that uses aggregation and utilizes the database's own efficient internal SQL functionality. So in my mind, the solution should look something like this:
return self.contacts.all().orders.all().aggregate(Sum('total'))
The problem is that I can't figure out how to properly write what I want Django/Python to do. Please help me!
Or am I mistaken and is the problem (or part of it) in my View-code?
<table>
<tr>
<th>Name</th>
<th>Order Count</th>
<th>Order Sum</th>
<th>Select</th>
</tr>
{% for company in company_list|slice:":100" %}
<tr>
<td>{{ company.name }}</td>
<td>{{ company.orders.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>- {{ contact.first_name }} {{ contact.last_name }}</td>
<td>Orders: {{ contact.orders.count }}</td>
<td> </td>
<td> </td>
</tr>
{% endfor %}
{% endfor %}
</table>
I would also appreciate any other hints and opinions on how this code could be further improved (especially from the performance POV).