2đź‘Ť
Whenever you think you have to do multiple descending loops like you have, think about whether or not you can approach the problem from the opposite end.
As @Pathetique pointed out, the following link shows how to minimise the number of queries you’re performing:
The highlight in that link is select_related
which only works on ForeignKeys
, and prefetch_related
which only works on ManyToManyFields
.
Since you were approaching this problem from the point of view of “I have a set of teams, now I want to show all the data associated with those teams”, you are unable to use any of the optimisations available since Team
does not have ForeignKeys
or ManyToManyFields
.
Instead, you can approach the problem like so “I want to show all Milestones, grouped by team and then by quality streams”. Since your Milestone class has access to all the data you require, it makes the queryset very easy to construct, only generating a single query.
def my_view(request):
queryset = Milestone.objects.select_related(
'team', 'quality_stream'
).order_by(
'team__name', 'quality_stream__name'
) # a single query to fetch all teams + streams + milestones
return render_to_response('/your/template.html',
{ 'milestones':queryset },
context_instance=RequestContext(request)
)
Now, your template is going to break the way you have it constructed. This is where the definition of the problem I mentioned before comes in. You have all your milestones, but you want to group them by team and then by quality stream. The ordering of our queryset helps us now, since we can iterate through all the milestones, and check whether we’re up to a new team or a new quality stream.
# your template
{% for milestone in milestones %}
{% ifchanged %} <p> {{ milestone.team.name }} </p> {% endifchanged %}
{% ifchanged %} <p> {{ milestone.quality_stream.name }} </p> {% endifchanged %}
<p> {{ milestone.name }} </p>
{% endfor %}
The above template uses the ifchanged template tags, which seems designed exactly for this purpose.
2đź‘Ť
There’s nothing wrong with what you are doing, but there may be some database optimization by doing your queries in a view, particularly using select_related():
Also, if your models had a bunch of fields but you only needed some you could use only() or defer(). I’ve seen substantial performance gains using defer to avoid large fields. only() is just the inverse of defer():
https://docs.djangoproject.com/en/1.5/ref/models/querysets/#defer
Your models don’t seem too complex so I think just using select_related() will work for you. I highly recommend using the Django debug toolbar for making optimization decisions. The debug toolbar would show you the actual select statements and the time it took for each of them. It’s good to know if there’s really a problem before spending too much time optimizing.
Hope this helps
- [Django]-Django Test – South migration reports 'no such table' but I can see said table in the db
- [Django]-Django restrict views by User permissions which are editable in the Admin
- [Django]-Django 1.8 error: 'NoneType' object is not callable
- [Django]-TypeError: Field 'classroom' expected a number but got (4,)
- [Django]-Django – how to send mail 5 days before event?