filter(** kwargs)返回包含匹配对象的新QuerySet 给定的查找参数。
查找参数(** kwargs)应采用上述格式 现场查找如下。多个参数通过AND连接在一起 基础SQL语句。
对我来说,它会返回原始集合中的项目子集。 但是我似乎错过了一些东西,因为下面的例子并不像我期望的那样:
>>> kids = Kid.objects.all()
>>> tuple(k.name for k in kids)
(u'Bob',)
>>> toys = Toy.objects.all()
>>> tuple( (t.name, t.owner.name) for t in toys)
((u'car', u'Bob'), (u'bear', u'Bob'))
>>> subsel = Kid.objects.filter( owns__in = toys )
>>> tuple( k.name for k in subsel )
(u'Bob', u'Bob')
>>> str(subsel.query)
'SELECT "bug_kid"."id", "bug_kid"."name" FROM "bug_kid" INNER JOIN "bug_toy" ON ("bug_kid"."id" = "bug_toy"."owner_id") WHERE "bug_toy"."id" IN (SELECT U0."id" FROM "bug_toy" U0)'
正如您在上面看到的那样, subsel 最终会返回重复的记录,这不是我想要的。我的问题是什么是正确的获取子集的方法? (注意:按定义设置不会出现多次出现的同一个对象)
解释为什么它的行为也很好,对于我来说 filter 意味着你用 filter()构建了什么-in函数在Python中。这是:采取满足要求的元素(换句话说,丢弃不符合要求的元素)。而这个定义似乎不允许引入/复制对象。
我知道可以完全 distinct(),但这仍然导致相当丑陋(可能比可能更慢)查询:
>>> str( subsel.distinct().query )
'SELECT DISTINCT "bug_kid"."id", "bug_kid"."name" FROM "bug_kid" INNER JOIN "bug_toy" ON ("bug_kid"."id" = "bug_toy"."owner_id") WHERE "bug_toy"."id" IN (SELECT U0."id" FROM "bug_toy" U0)'
我的 models.py 表示完整性:
from django.db import models
class Kid(models.Model):
name = models.CharField(max_length=200)
class Toy(models.Model):
name = models.CharField(max_length=200)
owner = models.ForeignKey(Kid, related_name='owns')
修改:
与@limelight聊天后得出结论是我的问题是我希望 filter()根据字典定义行事。并且它是如何在Python或任何其他理智的框架/语言中工作的。
更准确地说,如果我设置A = {x,y,z}
并调用A.filter( <predicate> )
,我不希望任何元素重复。使用Django的QuerySet,但它的行为如下:
A = {x,y,z}
A.filter( <predicate> )
# now A i.e. = {x,x}
首先,问题是不合适的方法名称(类似匹配()会更好)。 第二件事是我认为创建比Django允许的更有效的查询是可能的。我可能错了,如果我有一点时间,我可能会尝试检查是否属实。
答案 0 :(得分:9)
这有点难看,但有效(没有任何类型安全):
toy_owners = Toy.objects.values("owner_id") # optionally with .distinct()
Kid.objects.filter(id__in=toy_owners)
如果表现不成问题,我认为@limelights是对的。
PS!我在Django 1.6b2上测试了你的查询,得到了同样不必要的复杂查询。
答案 1 :(得分:2)
相反,DISTINCT可以使用GROUP BY(在django中注释)来获得不同的孩子。
toy_owners = Toy.objects.values_list("owner_id", flat=True).distinct()
Kid.objects.only('name').filter(pk__in=toy_owners).annotate(count=Count('owns'))