如何让Django的ORM检查模型是否具有某种关系?

时间:2012-06-07 10:39:04

标签: django django-models django-orm

我已经读过,避免使用大型IN子句是很糟糕的,因为它们很慢(特别是对于PostgreSQL)。

假设我有一个名为Fridge的课程,以及一个叫做蔬菜和调味品的课程。

这两者在他们和冰箱之间都有很多关系。

类似于:

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。

1 个答案:

答案 0 :(得分: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)

根据你的db后端和每个模型的行数,这可能会慢一些。