1

投稿モデルとタグモデルがあります。

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()

ブログエントリのリストと各投稿のタグのセットを出力する必要があります。このワークフローを使用して、2つのクエリでこれを実行できるようにしたいと思います。

  1. 投稿のリストを取得する
  2. それらの投稿で使用されているタグのリストを取得します
  3. タグを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)

私はそれを避ける方法を指摘するだれでも素晴らしいです。

4

2 に答える 2

4

この状況で私が通常行うことは次のとおりです。

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()) を追加するとよいでしょう。

于 2011-04-12T21:18:40.067 に答える
1

2 つのクエリでそれを使用する必要がある場合は、カスタム SQL が必要になると思います。

def custom_query(posts):
  from django.db import connection
  query = """
  SELECT "blogs_post_tags"."post_id", "blogs_tag"."title"
  FROM "blogs_post_tags"
  INNER JOIN "blogs_tags" ON ("blogs_post_tags"."tag_id"="blogs_tags"."id")
  WHERE "blogs_post_tags"."post_id" in %s
  """
  cursor=connection.cursor()
  cursor.execute(query,[posts,])
  results = {}
  for id,title in cursor.fetchall():
    results.setdefault(id,[]).append(title)
  return results

recent_posts = Post.objects.filter(published=True).order_by('-added')[:20]
post_ids = recent_posts.values_list('id',flat=True)
post_tags = custom_query(post_ids)

recent_postsPost QuerySet は、1 つのクエリからキャッシュする必要があります。
post_tags1 つのクエリからの投稿 ID からタグ タイトルへのマッピングです。

于 2011-04-12T15:01:55.457 に答える