我的代码如下所示:
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对象创建带有标签的字典?是否有可能避免迭代?
答案 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 %}