我有书籍和人物模型:
from django.db import models
class Book(models.Model):
author = models.ManyToManyField('Person')
class Person(models.Model):
name = models.CharField(max_length=16)
我在这里简化了一下。如何制作一个django查询来获取书籍的所有作者?使用SQL我会在中间表上进行选择并将其与人员表连接以获取名称,但我不确定如何在此处执行类似操作...当然,Person表中有人是不是书的作者,或者我可以得到Person.objects.all()。
答案 0 :(得分:3)
from django.db.models import Count
Person.objects.annotate(count_book=Count('book')).filter(count_book__gt=0)
为了好奇,我从这个主题提出的每种方式生成SQL:
In [9]: Person.objects.annotate(count_book=Count('book')).filter(count_book__gt=0)
DEBUG (0.000) SELECT "testapp_person"."id", "testapp_person"."name", COUNT("testapp_book_author"."book_id") AS "count_book" FROM "testapp_person" LEFT OUTER JOIN "testapp_book_author" ON ("testapp_person"."id" = "testapp_book_author"."person_id") GROUP BY "testapp_person"."id", "testapp_person"."name", "testapp_person"."id", "testapp_person"."name" HAVING COUNT("testapp_book_author"."book_id") > 0 LIMIT 21; args=(0,)
Out[9]: [<Person: Person object>]
In [10]: Person.objects.exclude(book=None)
DEBUG (0.000) SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" WHERE NOT (("testapp_person"."id" IN (SELECT U0."id" FROM "testapp_person" U0 LEFT OUTER JOIN "testapp_book_author" U1 ON (U0."id" = U1."person_id") LEFT OUTER JOIN "testapp_book" U2 ON (U1."book_id" = U2."id") WHERE (U2."id" IS NULL AND U0."id" IS NOT NULL)) AND "testapp_person"."id" IS NOT NULL)) LIMIT 21; args=()
Out[10]: [<Person: Person object>]
In [11]: Person.objects.filter(pk__in=Book.objects.values_list('author').distinct())
DEBUG (0.000) SELECT "testapp_person"."id", "testapp_person"."name" FROM "testapp_person" WHERE "testapp_person"."id" IN (SELECT DISTINCT U1."person_id" FROM "testapp_book" U0 LEFT OUTER JOIN "testapp_book_author" U1 ON (U0."id" = U1."book_id")) LIMIT 21; args=()
Out[11]: [<Person: Person object>]
也许这可以帮助您选择。
Personnaly,我更喜欢Chris的版本,因为它是最短的。另一方面,我不确定具有子查询的影响,这是其他两种方式的情况。也就是说,他们确实展示了令人感兴趣的QuerySet概念:
Annonation ,是查询集的每个值的聚合。如果您使用聚合(Count('book')),那么您将获得书籍总数。如果您使用注释(Count('book')),那么您将获得查询集的每个值的总数(每个人)。此外,每个人都有'count_book'属性,这非常酷:Person.objects.annotate(count_book=Count('book')).filter(count_book__gt=0)[0].count_book
子查询,对于创建复杂查询或优化查询非常有用(例如,合并查询集,通用关系预取)。
答案 1 :(得分:3)
最简单的方法:
Person.objects.filter(book__isnull=False)
这将选择至少有一本书与之相关的所有人。
答案 2 :(得分:1)
您可以非常轻松地使用作者的所有ID
Book.objects.all().values_list('author', flat=True).distinct()
正如jpic在下面指出的那样
Person.objects.filter(pk__in=Book.objects.values_list('author').distinct())
将为您提供所有人物对象,而不仅仅是他们的身份。
答案 3 :(得分:-1)
django本书的这一章用非常类似于你的例子来回答你所有的模型需求,包括ManyToMany关系。 http://www.djangobook.com/en/2.0/chapter10/