18

私は2つのモデルを持っています:

class Author(models.Model);
    name = models.CharField(max_length=255)

class Book(models.Model):
    title = models.CharField(max_length=255)
    authors = models.ManyToManyField(Author, null=True, blank=True)

今、私はすべての本の情報が欲しいです。だから、私はした:

book_info = Book.objects.all().values('title', 'authors__name')

そして、次のような出力が得られます (1 冊の本の著者が 2 人の場合):

[{'title': u'book1', 'authors__name': u'author1'},{'title': u'book1', 'authors__name': u'author2'}]

私が欲しかったのは次のようなものでした:

[{'title': u'book1', 'authors': [{'name':u'author1'},{'name':u'author2'}]}]

作成者モデルにはさらに多くのフィールドがある可能性があるため、それらのフィールドも取得したいと考えています。

これを単一のクエリで実行できますか?

望ましい結果のようなものを得るにはどうすればよいですか?

4

2 に答える 2

15

ジャンゴ1.4

素晴らしい質問です。prefetch_relatedを使用してください:

In [3]: [{'name': b.name, 'authors': [a.name for a in b.authors.all()]} for b in Book.objects.prefetch_related('authors')]
(0.000) SELECT "test_app_book"."id", "test_app_book"."name" FROM "test_app_book"; args=()
(0.000) SELECT ("test_app_book_authors"."book_id") AS "_prefetch_related_val", "test_app_author"."id", "test_app_author"."name" FROM "test_app_author" INNER JOIN "test_app_book_authors" ON ("test_app_author"."id" = "test_app_book_authors"."author_id") WHERE "test_app_book_authors"."book_id" IN (1, 2); args=(1, 2)
Out[3]: 
[{'authors': [u'a', u'b'], 'name': u'book'},
 {'authors': [u'b'], 'name': u'test'}]

ジャンゴ1.3

prefetch_related は Django 1.4 で導入されました。Django 1.3 では、 django-selectreverseが必要です:

In [19]: [{'name': b.name, 'authors': [a.name for a in b.authors_prefetch]} for b in Book.objects.select_reverse({'authors_prefetch': 'authors'})]
(0.000) SELECT "test_app_book"."id", "test_app_book"."name" FROM "test_app_book"; args=()
(0.001) SELECT (test_app_book_authors.book_id) AS "main_id", "test_app_author"."id", "test_app_author"."name" FROM "test_app_author" INNER JOIN "test_app_book_authors" ON ("test_app_author"."id" = "test_app_book_authors"."author_id") WHERE "test_app_book_authors"."book_id" IN (1, 2); args=(1, 2)
Out[19]: 
[{'authors': [u'a', u'b'], 'name': u'book'},
 {'authors': [u'b'], 'name': u'test'}]

django-selectreverse の使用:

class Book(models.Model):
    name = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author, null=True, blank=True)

    objects = ReverseManager()
于 2012-08-27T10:58:57.010 に答える