查询Q()无效,因为' set contains'在Django的相关领域?

时间:2016-03-30 04:53:35

标签: python sql django

我们说我们有一篮子水果。如何筛选出包含给定篮子中所有水果的篮子?

在本文档中https://docs.djangoproject.com/en/dev/ref/models/querysets/#in '在'方法似乎将返回任何包含任何给定水果的篮子。 有没有" set_contains"用于过滤的方法?比如Basket.objects.filter(fruit_set_containsAll = fruitSet)?

编辑:我发现Q()按预期无法正常工作。我将在这里发布测试:

class Basket(models.Model):
    weight = models.FloatField(default=1)
class Fruitname(models.Model):
    name = models.CharField(max_length=32)
class Fruit(models.Model):
    ofkind = models.ForeignKey(Fruitname, on_delete=models.CASCADE)  
    inbasket = models.ForeignKey(Basket, on_delete=models.CASCADE)  
    weight = models.FloatField(default=1)

将数据库设置为' apple'只在一个篮子里,'梨'在2个篮子里,' banana'在3篮子里:

print Basket.objects.all()
print Fruitname.objects.all()
[<Basket: id 31 has 4 fruits 
    1. id - 53 apple(28), weight 1.00
    2. id - 54 apple(28), weight 2.00
    3. id - 55 apple(28), weight 3.00
    4. id - 62 banana(30), weight 10.00
>, <Basket: id 32 has 2 fruits 
    1. id - 56 pear(29), weight 4.00
    2. id - 57 banana(30), weight 5.00
>, <Basket: id 33 has 4 fruits 
    1. id - 58 pear(29), weight 6.00
    2. id - 59 banana(30), weight 7.00
    3. id - 60 pear(29), weight 8.00
    4. id - 61 pear(29), weight 9.00
>]
[<Fruitname: apple(28)>, <Fruitname: pear(29)>, <Fruitname: banana(30)>]

如果我尝试使用&#39; apple&#39;和&#39; banana&#39;,它给出空集!!

print Basket.objects.filter(Q(fruit__ofkind__name__in=['apple'])&Q(fruit__ofkind__name__in=['banana'])).distinct()
[]

同样,

print Basket.objects.filter(Q(fruit__ofkind__name__in=['banana'])&Q(fruit__ofkind__name__in=['pear'])).distinct()
[]

以下是我如何使用&#39;&#39;过滤,它不是我需要的,它应该是一个空集。

print Basket.objects.filter(Q(fruit__ofkind__name__in=['apple','pear'])).distinct()
[<Basket: id 31 has 4 fruits 
    1. id - 53 apple(28), weight 1.00
    2. id - 54 apple(28), weight 2.00
    3. id - 55 apple(28), weight 3.00
    4. id - 62 banana(30), weight 10.00
>, <Basket: id 32 has 2 fruits 
    1. id - 56 pear(29), weight 4.00
    2. id - 57 banana(30), weight 5.00
>, <Basket: id 33 has 4 fruits 
    1. id - 58 pear(29), weight 6.00
    2. id - 59 banana(30), weight 7.00
    3. id - 60 pear(29), weight 8.00
    4. id - 61 pear(29), weight 9.00
>]

正常工作的唯一方法是使用过滤器进行链接:

Basket.objects.filter(fruit__ofkind__name__in=['apple']).filter(fruit__ofkind__name__in=['banana']).distinct()
[<Basket: id 31 has 4 fruits 
    1. id - 53 apple(28), weight 1.00
    2. id - 54 apple(28), weight 2.00
    3. id - 55 apple(28), weight 3.00
    4. id - 62 banana(30), weight 10.00
>]

这些代码使用Django 1.9.4进行测试 有没有解释?我暂时撤消接受的答案。

3 个答案:

答案 0 :(得分:1)

不确定这是否是最高效的方法,但至少它应该转换为一个(大的,丑的,嵌套的)sql事务(一旦评估了最终的baskets查询集):

baskets = Basket.objects.all()
for fruit in fruits:
    baskets = baskets.filter(id__in=fruit.basket.all())

可以尝试使用Q对象构建查询(在Dave Webb的answer to another question上构建),使用更优雅(可能更高性能)的方式:

queries = [Q(id__in=fruit.basket.all()) for fruit in fruits]

query = Q()

# AND the Q object with the ones in the list
for item in queries:
    query &= item

baskets = Basket.objects.filter(query)

答案 1 :(得分:1)

通过打印Q&amp ;;的原始SQL。操作,我已经找到了Q为什么这样做的原因。

from django.db import connection
print connection.queries
u'SELECT DISTINCT "market_basket"."id", "market_basket"."weight" FROM "market_basket" INNER JOIN "market_fruit" ON ("market_basket"."id" = "market_fruit"."inbasket_id") INNER JOIN "market_fruitname" ON ("market_fruit"."ofkind_id" = "market_fruitname"."id") WHERE ("market_fruitname"."name" IN (\'apple\') AND "market_fruitname"."name" IN (\'banana\')) LIMIT 21'

在单个过滤器中使用查询时,单个条件下不会满足 WHERE 子句的关键问题。它实际上是在['apple']和['banana']中寻找 fruitname 这是不可能的。我们需要的是找到(那些水果名为'apple'的水果)或(那些水果名为'banana'的水果)

目前唯一可行的解​​决方案是链式过滤器。

答案 2 :(得分:0)

要获得包含所有可用Basket个实例的Fruit,您可以执行以下操作:

from django.db.models import Count

# first get all PKs of fruits
fruit_pk_list = Fruit.objects.value_list('id', flat=True)

# Then get filter the basket with all fruits using annotate and Count
baskets = Basket.objects.annotate(
    num_fruit=Count('fruit')).filter(num_fruit=len(fruit_pk_list))