The prefetch_related()
method will execute a database query for each lookup you want to prefetch. Basically, here, Django will execute a first database query to get your Unit
instances and then two other queries to get the Order
and Report
instances.
So, once your Unit.obects.filter(...).prefetch_related(...)
queryset is executed, each Unit
instance will have its related Order
and Report
objects cached (no more database queries required to fetch these data).
views.py
Since Django 1.7, the prefetch_related()
method accepts a Prefetch
object. This Prefetch
object has a queryset
attribute that helps you to filter/order the related objects:
from django.shortcuts import render_to_response
def my_view(request):
units = Unit.objects.all().prefetch_related(
Prefetch(
'orders_set',
queryset=Order.objects.all().order_by('date'),
to_attr='prefetched_orders'
),
Prefetch(
'report_set',
queryset=Report.objects.all().order_by('submit_datetime'),
to_attr='prefetched_reports'
)
)
for unit in units:
unit.prefetched_orders = unit.prefetched_orders[:3]
unit.prefetched_reports = unit.prefetched_reports[:3]
return render_to_response('template.html', context={
'units': units
})
The to_attr
attribute let us store the related objects in a Python list
.
So, slicing those lists will not call the database anymore.
Now you have your newest orders and reports and you can build the object you want.
template.html
You can iterate over your units like that (the units
collection being the template context's units
object):
{% for unit in units %}
...
{% endfor %}
and then, you can browse the previously prefetched objects (tabular design with this code):
<table>
{% for unit in units %}
<tr>
<td>{{ unit.field_to_display }}</td>
{% for order in unit.prefetched_orders %}
<td>{{ order.field_to_display}}</td>
{% endfor %}
{% for report in unit.prefetched_reports %}
<td>{{ report.field_to_display}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
More info about the templating language can be found in the official doc.