我试图弄清楚如何使用select_related
或prefetch_related
来优化来自外键另一端的查询。例如:
说我有一些模型如下:
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")
如果我想要打印所有ProductImage
,我必须遍历所有产品,然后,对于每个产品,迭代所有产品图像。但是,这会产生O(n * m)个数据库查询。
for product in Product.objects.all():
print product.product_images.all()
我想知道是否有办法利用select_related
或prefetch_related
将此查询减少到一个或两个查询。
正如Django所记录的那样,当我选择select_related
时,我可以让ProductImage
工作。如您所见,添加select_related
会在产品表中创建JOIN。
>>> 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 ....
但是,如何完成相反的操作呢?例如,如何查询所有Product
并将其加入ProductImage
s?做类似以下的事情似乎无法奏效。
Product.objects.select_related('product_images').query.sql_with_params()
在Django中是否可以这样?
感谢您的考虑。
答案 0 :(得分:8)
这正是prefetch_related
的作用。
Product.objects.prefetch_related('product_images')
但是,使用query.sql_with_params()
进行诊断是没有意义的:prefetch_related
执行两个查询,第二个查询不会显示在那里。您应该使用django.db.connection.queries
来检查Django正在进行的查询,或者更好地使用Django调试工具栏向您显示。
答案 1 :(得分:3)
select_related
,并且当存在反向外键关系时应使用prefetch_related
。