Django:使用最少的查询集检索ManyToManyField对象

时间:2013-11-26 08:16:20

标签: django

我的代码如下所示:

models.py

class Tag(models.Model):
    name = models.CharField(max_length=42)

class Post(models.Model):
    user = models.ForeignKey(User, related_name='post')
    #...various fields...
    tags = models.ManyToManyField(Tag, null=True)

views.py

posts = Post.objects.all().values('id', 'user', 'title')
tags_dict = {}
for post in posts: # Iteration? Why?
    p = Post.objects.get(pk=[post['id']])  # one extra query? Why?
    tags_dict[post['id']] = p.tags.all()

我应该如何使用最少的查询集为每个Post对象创建带有标签的字典?是否有可能避免迭代?

2 个答案:

答案 0 :(得分:2)

是的,你需要一个循环。但是您可以在每次迭代中保存一个额外的查询,您不需要获取post对象来获取其所有标记。您可以直接在Tag模型上查询以获取与帖子ID相关的标记:

for post in posts:
    tags_dict[post['id']] = Tag.objects.filter(post__id=post['id'])

或者使用Dict理解来提高效率:

tags_dict = {post['id']: Tag.objects.filter(post__id=post['id']) for post in posts}

答案 1 :(得分:1)

如果你有Django版本> = 1.4并且不需要字典,但需要减少查询次数,你可以像这样使用this method

posts = Post.objects.all().only('id', 'user', 'title').prefetch_related('tags')

似乎只执行了2个查询(一个用于Post,另一个用于Tag和INNER JOIN。

然后您可以在没有额外查询的情况下访问post.tags.all,因为标签已经被预取。

{% for post in posts %}
    {% for tag in post.tags.all %}
        {{ tag.name }}
     {% endfor %}
{% endfor %}