Reputation: 991
I have an Item
object which has a ForeignKey to a Receipt
object.
class Receipt(models.Model):
...
class Item(models.Model):
receipt = models.ForeignKey(Receipt)
name = models.CharField(max_length=255)
cost = models.DecimalField(default=0, max_digits=6, decimal_places=3)
...
I display the receipts using a generic view.
class ReceiptView(DetailView):
model = Receipt
And then on the template, I want to show all items on the receipt.
<ul>
{% for item in object.item_set.all %}
<li>{{ item.name }}</li>
{% endfor %}
</ul>
This works fine for smaller data sets. One of the receipt objects has 1600 items related to it. Loading the page for that receipt is incredibly slow. Using Django Debug Toolbar I notice that Django is executing 1 query per item.
If I alter the list item in the template so that rather than displaying a property of the item, I just display the item itself, Django just executes a single query.
<ul>
{% for item in object.item_set.all %}
<li>{{ item }}</li>
{% endfor %}
</ul>
Unfortunately I need to display about 10 of the item's properties in the template. Is there someway I can tell Django to execute a single query to get all items and all of their properties?
Upvotes: 0
Views: 1167
Reputation: 4445
Use prefetch_related
. Since you are doing a reverse foreign key lookup, you're essentially working with a ManyToMany relationship. prefetch_related
will do a separate query under the hood, to retrieve and then cache all of the Receipt
objects for you.
Since you're using generic views, rather than specifying a model
, you can specify a queryset
.
class ReceiptView(DetailView):
queryset = Receipt.objects.prefetch_related('related_items')
In order to do this, you'll have to specify a related_name
in your Item
model:
class Item(models.Model):
receipt = models.ForeignKey(Receipt, related_name='related_items')
Upvotes: 1