我的模特:
class Book(models.Model):
title = models.CharField(max_length=254)
subtitle = models.CharField(max_length=254, null=True, blank=True)
subjects = models.ManyToManyField(Subject)
class Subject(models.Model):
name = models.CharField(max_length=255)
description = models.CharField(max_length=254, null=True, blank=True)
这里的书籍主题与主题模型存在多对多的关系。
我如何才能获得所有相同主题的书籍。 例如,所有具有主题id [2,3,6]
的书籍答案 0 :(得分:0)
Q
个对象的解决方案无效。
一些初步数据:
>>> from subjects.models import Subject, Book
>>> s1 = Subject.objects.create(name='subject_1', description='description 1')
>>> s2 = Subject.objects.create(name='subject_2', description='description 2')
>>> s3 = Subject.objects.create(name='subject_3', description='description 3')
>>> s4 = Subject.objects.create(name='subject_4', description='description 4')
>>> b1 = Book.objects.create(title='one_subject_book', subtitle='one subject')
>>> b1.subjects = [s1]
>>> b2 = Book.objects.create(title='three_subject_book', subtitle='three subjects')
>>> b2.subjects = [s2,s3,s4]
>>> b3 = Book.objects.create(title='four_subject_book', subtitle='four subjects')
>>> b3.subjects = [s1,s2,s3,s4]
让我们先用subjects__in=[s1,s2,s3]
检查天真的方法。我们只搜索一本书,因为只有b3
包含所有科目。
>>> Book.objects.filter(subjects__in=[s1,s2,s3])
DEBUG (0.001)
SELECT `subjects_book`.`id`, `subjects_book`.`title`, `subjects_book`.`subtitle`
FROM `subjects_book`
INNER JOIN `subjects_book_subjects` ON ( `subjects_book`.`id` = `subjects_book_subjects`.`book_id` )
WHERE `subjects_book_subjects`.`subject_id` IN (1, 2, 3)
LIMIT 21; args=(1, 2, 3)
[<Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>, <Book: Book object>]
我们只是搜索包含books
或s1
或s2
的{{1}}。这就是为什么我们得到这样的结果。我们有重复的结果,因为我们没有使用s3
现在让我们试试.distinct()
个对象。
只想提一下:
Q
与:
相同Book.objects.filter(Q(subjects=s1)&Q(subjects=s2)&Q(subjects=s3))
只是一个更动态的版本,您可以使用Book.objects.filter(reduce(lambda q1,q2: q1&q2, [Q(subjects=s) for s in [s1,s2,s3]]))
轻松更改列表。
subjects
我们得到了空结果集。如果您检查查询,这将是正常的。我们不能同时包含三个不同的>>> Book.objects.filter(reduce(lambda q1,q2: q1&q2, [Q(subjects=s) for s in [s1,s2,s3]]))
DEBUG (0.260)
SELECT `subjects_book`.`id`, `subjects_book`.`title`, `subjects_book`.`subtitle`
FROM `subjects_book`
INNER JOIN `subjects_book_subjects` ON ( `subjects_book`.`id` = `subjects_book_subjects`.`book_id` )
WHERE (
`subjects_book_subjects`.`subject_id` = 1
AND `subjects_book_subjects`.`subject_id` = 2
AND `subjects_book_subjects`.`subject_id` = 3
) LIMIT 21; args=(1, 2, 3)
[]
值。
我们得到此类查询的原因是因为我们在单subject_id
语句中同时应用了所有Q
过滤器。请在Spanning multi-valued relationships了解详情。
为了从.filter
的角度获得正确的结果,我们必须为我们想要过滤的每个MySQL
加入subjects_book_subjects
表。在subject
视角中,这可以通过一系列连续的ORM
语句来实现:
.filter
以更时尚的方式看待这个:
Book.objects.filter(subjects=s1).filter(subjects=s2).filter(subjects=s3)
例如:
books_queryset = reduce(lambda books,s: books.filter(subjects=s),[s1,s2,s3], Book.objects.all())