def nr_failures(self): last_year = make_aware(datetime.today() - timedelta(days=365), get_current_timezone()) return FailureMaintenance.objects.filter(apparaat=self, type__failure_maintenance='F', start_dt__gte=last_year, ).count() def nr_maintenance(self): last_year = make_aware(datetime.today() - timedelta(days=365), get_current_timezone()) return FailureMaintenance.objects.filter(apparaat=self, type__failure_maintenance='M', start_dt__gte=last_year, ).count()
Views.py
eq = PieceOfEquipment.objects.filter(client=client) return render(request, 'meldman/overview_equipm.html', {'eq': eq})
HTML template
<td style="text-align:left”> <a href="{% url 'some_url' %}?device={{ eq.id }}">{{ eq.nr_failures }} <td style="text-align:left”> <a href="{% url 'some_url' %}?device={{ eq.id }}">{{ eq.nr_maintenance }}
Beautiful, relative simple code with the logic stored in the model (as most blogs tell you to do). Well done, pat on the shoulder.
And this worked fine, however, somehow clients seemed to register more and more equipment which they tracked in the “Meldman” (which I guess can be seen is good news, seemingly they like the application…). The result was that the peformance began te degrade to a level which was not acceptable anymore. So, what was happening? Using the Django-debug-toolbar it was quickly evident that one (expensive) query was used over-and-over again. If a client has 300 pieces of equipment a similar query would run 300 time for calculating the “nr_failures” and 300 times for calculating the “nr_maintenance”.
So, what did we change:
1) we stopped using the properties on the model
2) we changed the view to:
from django.db.models import Count, Q last_year = make_aware(datetime.today() - timedelta(days=365), get_current_timezone()) eq = Equipment.objects.filter(Q(klant=klant) & Q(FailureMaintenance__start_dt__gte=last_year)) eq = eq.annotate(nr_failures=Count('failuremaintenance', filter=Q(failuremaintenance__type__failure_maintenance='F'))) eq = eq.annotate(nr_maintenance=Count('failuremaintenance', filter=Q(failuremaintenance__type__failure_maintenance='M'))) return render(request, 'meldman/overview_equipm.html', {'eq': eq})
Now, no matter how many pieces of equipment a client has only one query (yes, “1”, as in “the first positive integer”) is executed. Obviously this solved the performance problem quite handsomely.
All in all a fairly painless exercise with a huge benefit.