1

我读过避免使用大的 IN 子句是不好的,因为它们很慢(尤其是 PostgreSQL)。

假设我有一门课叫冰箱,还有一门课叫蔬菜和调味品。

这两者在自己和冰箱之间都有多对多关系。

所以像:

class Fridge(models.Model):
     condiments = models.ManyToManyField(Condiments)
     vegetables = models.ManyToManyField(Vegetables)

这里我们有一个 QuerySet 代表我们的白色冰箱:

qs = Fridges.objects.filter(color='white')

第一个问题

“给定一份调味品 ID 列表,给我所有的冰箱,里面有任何调味品(修改原始的 QuerySet)。”

第二个查询

“给定一个蔬菜 ID 列表,给我所有的冰箱,里面有所有这些蔬菜(修改原来的 QuerySet)。”

如果不构建冰箱 ID 列表并在我的查询集中添加 IN 子句,我到底该怎么做呢?

以下是使用 IN 子句的解决方案(我现有解决方案的名称更改版本):

第一个查询:

    condiment_ids = [...] # list of condiment IDs
    condiments = Condiment.objects.filter(
        id__in=condiment_ids).all()
    condiment_fridges = None
    for condiment in condiments:
        qs = condiment.fridge_set.all()
        if not condiment_fridges:
            condiment_fridges = qs
        else:
            condiment_fridges = condiment_fridges | qs
    qs = qs.filter(id__in=[l.id for l in condiment_fridges])

第二个查询:

    vegetable_ids = [...] # list of vegetable IDs
    vegetables = vegetable.objects.filter(id__in=vegetable_ids).all()
    vegetable_fridges = None
    for vegetable in vegetables:
        qs = vegetable.location_set.all()
        if not vegetable_fridges:
            vegetable_fridges = qs
        else:
            vegetable_fridges = vegetable_fridges & qs
    qs = qs.filter(id__in=[l.id for l in vegetable_fridges])

这些解决方案看起来很可怕而且很老套,我想知道是否有更好的方法来使用 Django 的 ORM 来解决这些问题。

4

1 回答 1

1

除非我误解了这个问题,否则您只需要:

Fridge.objects.filter(condiments__in=[1,2,3,4,5])

可能有一种更有效的方法来确定冰箱是否有所有的调味品。未经测试,但类似:

max_conds = Condiment.objects.all().count()
result = Fridge.objects.annotate(conds=Count('condiments')).filter(conds=max_conds)

尽管取决于您的数据库后端和每个模型的行数,但这可能会更慢。

于 2012-06-07T19:21:55.247 回答