Django - 如何使用QuerySet过滤来获取对象的子集?

elm*_*lmo 5 python django

根据文件:

filter(**kwargs)返回包含与给定查找参数匹配的对象的新QuerySet.

查找参数(**kwargs)应采用下面的字段查找中描述的格式.多个参数通过基础SQL语句中的AND连接.

对我来说,这表明它将返回原始集合中的项目子集.但是我似乎错过了一些东西,因为下面的示例并不像我期望的那样:

>>> 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)'
Run Code Online (Sandbox Code Playgroud)

正如你在上面看到的那样,subsel最终会返回重复的记录,这不是我想要的.我的问题是获得子集的正确方法是什么?(注意:按定义设置不会出现多次出现的同一个对象)

解释为什么它的行为也会很好,因为我过滤意味着你在Python中使用filter()内置函数实现了什么.这是:采取满足要求的元素(换句话说,丢弃不符合要求的元素).而这个定义似乎不允许引入/复制对象.

我知道可以完全区分(),但仍然导致相当丑陋(可能比可能更慢)查询:

>>> 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)'
Run Code Online (Sandbox Code Playgroud)

我的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')
Run Code Online (Sandbox Code Playgroud)

编辑:

在与@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}
Run Code Online (Sandbox Code Playgroud)

所以首先问题是不合适的方法名称(比如match()会更好).第二件事是我认为创建比Django允许的更有效的查询是可能的.我可能错了,如果我有一点时间,我可能会尝试检查是否属实.

chl*_*nde 9

这有点难看,但有效(没有任何类型安全):

toy_owners = Toy.objects.values("owner_id")  # optionally with .distinct()
Kid.objects.filter(id__in=toy_owners)
Run Code Online (Sandbox Code Playgroud)

如果性能不是问题,我认为@limelights是对的.

PS!我在Django 1.6b2上测试了你的查询并得到了同样不必要的复杂查询.