Python Django ORM:选择相关集

Python Django ORM:选择相关集,python,django,orm,Python,Django,Orm,假设我有两种型号: class Poll(models.Model): category = models.CharField(u"Category", max_length = 64) [...] class Choice(models.Model): poll = models.ForeignKey(Poll) [...] 给定一个轮询对象,我可以通过以下方式查询其选择: poll.choice_set.all() 但是,是否有一个实用函数可以查询一组投

假设我有两种型号:

class Poll(models.Model):
    category = models.CharField(u"Category", max_length = 64)
    [...]

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    [...]
给定一个轮询对象,我可以通过以下方式查询其选择:

poll.choice_set.all()
但是,是否有一个实用函数可以查询一组投票中的所有选择

事实上,我正在寻找类似于以下内容的内容(不受支持,我也不寻求它是如何实现的):

我制作了一个(丑陋的)函数来帮助我实现:

def qbind(objects, target_name, model, field_name):
    objects = list(objects)
    objects_dict = dict([(object.id, object) for object in objects])
    for foreign in model.objects.filter(**{field_name + '__in': objects_dict.keys()}):
        id = getattr(foreign, field_name + '_id')
        if id in objects_dict:
            object = objects_dict[id]
            if hasattr(object, target_name):
                getattr(object, target_name).append(foreign)
            else:
                setattr(object, target_name, [foreign])
    return objects
其用途如下:

polls = Poll.objects.filter(category = 'foo')
polls = qbind(polls, 'choices', Choice, 'poll')
# Now, each object in polls have a 'choices' member with the list of choices.
# This was achieved with 2 SQL queries only.
Django是否已经提供了更简单的功能?或者至少,一个片段以更好的方式做同样的事情


你通常是如何处理这个问题的?

我想你说的是,“我想要一组民意测验的所有选择。”如果是这样,试试这个:

polls = Poll.objects.filter(category='foo')
choices = Choice.objects.filter(poll__in=polls)

我认为您正在尝试的是子数据的术语“急切加载”——这意味着您正在为每个轮询加载子列表(选项集),但都是在第一个查询中加载到DB,这样您就不必在以后进行大量查询

如果这是正确的,那么您要查找的是“选择相关的”-请参阅

我注意到您尝试了“选择相关”,但没有成功。你能试着做“选择相关”然后过滤吗。这可能会解决它



更新:这不起作用,请参阅下面的注释。

更新:自Django 1.4以来,此功能内置:请参阅

第一个答案:不要浪费时间编写qbind之类的东西,除非您已经编写了一个工作应用程序,对其进行了分析,并证明N查询实际上是数据库和负载场景的性能问题

但也许你已经做到了。所以第二个答案是:qbind()完成了您需要做的事情,但是如果打包在一个自定义QuerySet子类中,并附带一个返回自定义QuerySet实例的Manager子类,那么它将更加惯用。理想情况下,您甚至可以使它们通用并可用于任何反向关系。然后你可以做一些类似的事情:

Poll.objects.filter(category='foo').fetch_reverse_relations('choices_set')

有关Manager/QuerySet技术的示例,请参阅,它解决了类似的问题,但对于通用外键的情况,不是反向关系。要将qbind()函数的精髓与此处显示的结构结合起来,为您的问题提供一个非常好的解决方案并不难。

时间已经过去,随着QuerySet函数的引入,该功能现在在Django 1.4中可用。此功能有效地执行建议的
qbind
功能所执行的操作。执行了两个查询,并且连接发生在PythonLand中,但现在这是由ORM处理的

原始查询请求现在将变成:

polls = Poll.objects.filter(category = 'foo').prefetch_related('choice_set')
如以下代码示例所示,
polls
QuerySet可用于获取每个
Poll
的所有
Choice
对象,而无需进一步访问数据库:

for poll in polls:
    for choice in poll.choice_set:
        print choice

+1我不知道这个功能!多么优雅啊!这就是我在
qbind
函数开头所做的。但实际上,我想要的是每次投票的选择集,而不是整个选择集。例如,如果我想在模板上显示投票列表以及每个投票的选项,我不想为每个投票点击数据库。
qbind
功能的要点是将您的
polls
choices
数据连接在一起以实现这一点。如果a正在查询Choice并希望预加载每个相应的Poll,则select\u related将非常有用。但是在这里,我想要的是select_related不支持的相反情况(想想相应的SQL查询,如果不复制大量数据,它不能在一个查询中完成。)这应该在两个查询中完成。是的,你是对的。很抱歉没有看到。由于“choice_set”在对查询求值之前不可用,因此它甚至无法识别它是否存在。也许您的qbind函数是最好的。但是,将其打包到自定义管理器中,并使用+1进行后续操作可能是有意义的。对于任何从google无意中访问此页面的人来说,这是最好的解决方案。我使用Django 1.6,在python shell中使用时,会得到类型错误相关的管理器对象。我和Frederic做了完全相同的事情:Choice有外键投票,所以两者之间有1:n的关系。投票和choice@Timo您应该调用
poll.choice\u set.all()
for poll in polls:
    for choice in poll.choice_set:
        print choice