我有 Post 和 Tag 模型:
class Tag(models.Model):
""" Tag for blog entry """
title = models.CharField(max_length=255, unique=True)
class Post(models.Model):
""" Blog entry """
tags = models.ManyToManyField(Tag)
title = models.CharField(max_length=255)
text = models.TextField()
我需要为每个帖子输出博客条目列表和一组标签。我希望能够使用此工作流仅通过两个查询来执行此操作:
- 获取帖子列表
- 获取这些帖子中使用的标签列表
- 将标签链接到 python 中的帖子
我在最后一步遇到了问题,这是我想出的代码,但是给了我 'Tag' object has no attribute 'post__id'
#getting posts
posts = Post.objects.filter(published=True).order_by('-added')[:20]
#making a disc, like {5:<post>}
post_list = dict([(obj.id, obj) for obj in posts])
#gathering ids to list
id_list = [obj.id for obj in posts]
#tags used in given posts
objects = Tag.objects.select_related('post').filter(post__id__in=id_list)
relation_dict = {}
for obj in objects:
#Here I get: 'Tag' object has no attribute 'post__id'
relation_dict.setdefault(obj.post__id, []).append(obj)
for id, related_items in relation_dict.items():
post_list[id].tags = related_items
你能看到那里的错误吗?如何使用 django ORM 解决此任务,否则我将不得不编写自定义 SQL?
编辑:
我能够通过原始查询解决这个问题:
objects = Tag.objects.raw("""
SELECT
bpt.post_id,
t.*
FROM
blogs_post_tags AS bpt,
blogs_tag AS t
WHERE
bpt.post_id IN (""" + ','.join(id_list) + """)
AND t.id = bpt.tag_id
""")
relation_dict = {}
for obj in objects:
relation_dict.setdefault(obj.post_id, []).append(obj)
如果有人指出如何避免它,我将非常感激。
最佳答案
在这种情况下,我通常会这样做:
posts = Post.objects.filter(...)[:20]
post_id_map = {}
for post in posts:
post_id_map[post.id] = post
# Iteration causes the queryset to be evaluated and cached.
# We can therefore annotate instances, e.g. with a custom `tag_list`.
# Note: Don't assign to `tags`, because that would result in an update.
post.tag_list = []
# We'll now need all relations between Post and Tag.
# The auto-generated model that contains this data is `Post.tags.through`.
for t in Post.tags.through.select_related('tag').filter(post_id__in=post):
post_id_map[t.post_id].tag_list.append(t.tag)
# Now you can iterate over `posts` again and use `tag_list` instead of `tags`.
如果以某种方式封装此模式会更好,因此您可能希望添加一个 QuerySet 方法(例如 select_tags()
)来为您完成此操作。
关于python - Django:优化多对多查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5636482/