I'm trying to figure out how to use select_related
or prefetch_related
to optimize a query from the other end of a foreign key. For example:
Say I have some models such as the following:
class Product(models.Model):
name = models.CharField(max_length=50)
class ProductImage(models.Model):
image = models.ImageField(upload_to="images")
product = models.ForeignKey("myapp.Product", related_name="product_images")
If I want to print all of the ProductImage
, I have to iterate through all of the products and then, for each product, iterate through all of the product images. However, this produces O(n * m) database queries.
for product in Product.objects.all():
print product.product_images.all()
I'm wondering if there is a way to utilize select_related
or prefetch_related
to reduce this lookup to one or two queries.
As documented by Django, I can get select_related
to work when I select ProductImage
. As you can see, adding the select_related
creates a JOIN to the product table.
>>> ProductImage.objects.all().query.sql_with_params()
(u'SELECT "myapp_productimage"."id", ... FROM "myapp_productimage" ....
>>> ProductImage.objects.select_related('product').query.sql_with_params()
(u'SELECT "myapp_productimage"."id", ... FROM "myapp_productimage" LEFT OUTER JOIN ....
However, how do I accomplish the reverse? For example, how do I query all of the Product
s and have it JOIN on the ProductImage
s? Doing something like the following doesn't seem to work.
Product.objects.select_related('product_images').query.sql_with_params()
Is something like this possible in Django?
Thanks for your consideration.
That is exactly what prefetch_related
does.
Product.objects.prefetch_related('product_images')
However, there's no point in using query.sql_with_params()
to diagnose this: prefetch_related
does two queries, and the second one won't show up there. You should use django.db.connection.queries
to examine the queries that Django is making, or even better use the Django debug toolbar to show you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With