2014-03-29 70 views
5

我想弄清楚如何使用select_relatedprefetch_related优化来自外键另一端的查询。例如:Django在外键上正确使用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_relatedprefetch_related这个查找减少到一个或两个查询的方式。

正如Django所记录的,当我选择ProductImage时,我可以得到select_related。如您所见,添加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?做类似下面的事情似乎并不奏效。

Product.objects.select_related('product_images').query.sql_with_params() 

在Django中是这样的可能吗?

感谢您的考虑。

回答

8

这正是prefetch_related所做的。

Product.objects.prefetch_related('product_images') 

然而,有一个在使用query.sql_with_params()诊断这是没有意义的:prefetch_related确实查询,而第二个将不会出现在那里。您应该使用django.db.connection.queries来检查Django正在进行的查询,或者更好地使用Django调试工具栏来向您显示。

+0

非常感谢Daniel。另外,很高兴知道sql_with_params()没有显示完整的图片。我会尝试使用您建议的其他方法。 –

3

select_related在您有正向外键关系时使用,当存在反向外键关系时应该使用prefetch_related