我们说我们有一篮子水果。如何筛选出包含给定篮子中所有水果的篮子?
在本文档中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进行测试 有没有解释?我暂时撤消接受的答案。
答案 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))