python Django ORM:选择相关集
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/853184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Django ORM: Selecting related set
提问by Frédéric Jolliton
Say I have 2 models:
假设我有 2 个模型:
class Poll(models.Model):
category = models.CharField(u"Category", max_length = 64)
[...]
class Choice(models.Model):
poll = models.ForeignKey(Poll)
[...]
Given a Poll object, I can query its choices with:
给定一个 Poll 对象,我可以查询它的选择:
poll.choice_set.all()
But, is there a utility function to query all choices from a set of Poll?
但是,是否有一个实用函数可以从一组 Poll 中查询所有选项?
Actually, I'm looking for something like the following (which is not supported, and I don't seek how it could be):
实际上,我正在寻找类似于以下内容的内容(不受支持,而且我不寻求它是如何实现的):
polls = Poll.objects.filter(category = 'foo').select_related('choice_set')
for poll in polls:
print poll.choice_set.all() # this shouldn't perform a SQL query at each iteration
I made an (ugly) function to help me achieve that:
我做了一个(丑陋的)函数来帮助我实现这一目标:
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
which is used as follow:
其用法如下:
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.
Is there something easier already provided by Django? Or at least, a snippet doing the same thing in a better way.
Django 已经提供了一些更简单的东西吗?或者至少,一个片段以更好的方式做同样的事情。
How do you handle this problem usually?
你通常如何处理这个问题?
采纳答案by Carl Meyer
Update: Since Django 1.4, this feature is built in: see prefetch_related.
更新:自 Django 1.4 起,此功能已内置:请参阅prefetch_related。
First answer: don't waste time writing something like qbind until you've already written a working application, profiled it, and demonstrated that N queries is actually a performance problem for your database and load scenarios.
第一个答案:不要浪费时间编写类似 qbind 的东西,直到您已经编写了一个工作应用程序,对其进行了分析,并证明了 N 查询实际上是您的数据库和负载场景的性能问题。
But maybe you've done that. So second answer: qbind() does what you'll need to do, but it would be more idiomatic if packaged in a custom QuerySet subclass, with an accompanying Manager subclass that returns instances of the custom QuerySet. Ideally you could even make them generic and reusable for any reverse relation. Then you could do something like:
但也许你已经这样做了。所以第二个答案: qbind() 做你需要做的事情,但如果打包在一个自定义的 QuerySet 子类中,它会更惯用,附带一个返回自定义 QuerySet 实例的 Manager 子类。理想情况下,您甚至可以使它们通用且可重用于任何反向关系。然后你可以做这样的事情:
Poll.objects.filter(category='foo').fetch_reverse_relations('choices_set')
For an example of the Manager/QuerySet technique, see this snippet, which solves a similar problem but for the case of Generic Foreign Keys, not reverse relations. It wouldn't be too hard to combine the guts of your qbind() function with the structure shown there to make a really nice solution to your problem.
有关 Manager/QuerySet 技术的示例,请参阅此代码段,它解决了类似的问题,但对于通用外键的情况,而不是反向关系。将 qbind() 函数的内容与那里显示的结构结合起来,为您的问题提供一个非常好的解决方案并不太难。
回答by Austin Phillips
Time has passed and this functionality is now available in Django 1.4 with the introduction of the prefetch_related()QuerySet function. This function effectively does what is performed by the suggested qbind
function. ie. Two queries are performed and the join occurs in Python land, but now this is handled by the ORM.
随着时间的流逝,随着prefetch_related()QuerySet 函数的引入,此功能现在在 Django 1.4 中可用。此函数有效地执行建议qbind
函数执行的操作。IE。执行两个查询并且连接发生在 Python 域中,但现在这由 ORM 处理。
The original query request would now become:
原来的查询请求现在变成:
polls = Poll.objects.filter(category = 'foo').prefetch_related('choice_set')
As is shown in the following code sample, the polls
QuerySet can be used to obtain all Choice
objects per Poll
without requiring any further database hits:
如以下代码示例所示,polls
QuerySet 可用于获取Choice
per 的所有对象,Poll
而无需任何进一步的数据库命中:
for poll in polls:
for choice in poll.choice_set:
print choice
回答by a paid nerd
I think what you're saying is, "I want all Choices for a set of Polls." If so, try this:
我想你的意思是,“我想要一组民意调查的所有选项。” 如果是这样,试试这个:
polls = Poll.objects.filter(category='foo')
choices = Choice.objects.filter(poll__in=polls)
回答by NathanD
I think what you are trying to do is the term "eager loading" of child data - meaning you are loading the child list (choice_set) for each Poll, but all in the first query to the DB, so that you don't have to make a bunch of queries later on.
我认为您正在尝试做的是术语“急切加载”子数据 - 意味着您正在为每个 Poll 加载子列表(choice_set),但所有这些都在对数据库的第一个查询中,因此您没有稍后进行一堆查询。
If this is correct, then what you are looking for is 'select_related' - see https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related
如果这是正确的,那么您正在寻找的是“select_related” - 请参阅https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related
I noticed you tried 'select_related' but it didn't work. Can you try doing the 'select_related' and then the filter. That might fix it.
我注意到您尝试了“select_related”,但没有奏效。您可以尝试先执行“select_related”,然后再执行过滤器。那可能会解决它。
UPDATE: This doesn't work, see comments below.
更新:这不起作用,请参阅下面的评论。