【问题标题】:How to select many to one to many without hundreds of queries using Django ORM?如何在不使用 Django ORM 的数百个查询的情况下选择多对一对多?
【发布时间】:2012-05-06 12:18:15
【问题描述】:

我的数据库具有以下架构:

class Product(models.Model):
    pass

class Tag(models.Model):
    product = models.ForeignKey(Product)
    attr1 = models.CharField()
    attr2 = models.CharField()
    attr3 = models.CharField()

class AlternatePartNumber(models.Model):
    product = models.ForeignKey(Product)

换句话说,Product 有很多 Tags,Product 有很多 AlternatePartNumbers。 Tags 是Product 的属性集合。

鉴于Tag 中的三个属性,我想选择匹配的关联Products(可能不止一个),以及每个产品的所有AlternatePartNumbers。

目前我这样做:

# views.py
results = Tag.objects.
    filter(attr1=attr1).
    filter(attr2=attr2).
    filter(attr3=attr3)

# a template
{% for result in results %}
    {% for alternate in result.product.alternatepartnumber_set.all %}
        {{ alternate.property }}
    {% endfor %}
{% endfor %}

这可以运行数千个查询,具体取决于匹配的数量。有没有好的方法来优化这个?我尝试使用Tag.objects.select_related().filter...,这对一些人有所帮助,但还不够。

【问题讨论】:

    标签: python django django-models query-optimization django-orm


    【解决方案1】:

    Product和AlternatePartNumber的关系是反向ForeignKey关系,所以select_related()不起作用。你需要prefetch_related(),它比select_related() 没有那么激进,但可以处理多对一的关系。

    我自己之前没有使用过 prefetch_related(),但如果我正确地阅读了the documentation,你需要像Tag.objects.prefetch_related('product__alternatepartnumber_set').filter... 这样的东西。如果这不起作用,请在 AlternatePartNumber 模型上指定一个 related_name 并使用它来代替 alternatepartnumber_set

    【讨论】:

    • 我不得不添加related_name,但是使用prefetch_related 大大减少了查询的数量。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-06
    • 1970-01-01
    • 2015-09-17
    • 2017-06-27
    • 2013-05-19
    相关资源
    最近更新 更多