Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 具有多对多字段的django过滤器模型_Python_Django - Fatal编程技术网

Python 具有多对多字段的django过滤器模型

Python 具有多对多字段的django过滤器模型,python,django,Python,Django,我的模型: 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.CharFie

我的模型:

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]的书籍

带有
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]
让我们首先用
主题检查天真的方法。因此,我们只寻找一本书,因为只有
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>]
同:

Book.objects.filter(reduce(lambda q1,q2: q1&q2, [Q(subjects=s) for s in [s1,s2,s3]]))
这是一个更具动态性的版本,您可以轻松地使用
主题更改列表

>>> 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\u id
值。 我们得到这样一个查询的原因是,我们在一个
.filter
语句中同时应用了所有
Q
过滤器。更多关于这方面的信息,请访问

为了从
MySQL
的角度获得正确的结果,我们必须为每个
主题
加入
subjects\u book\u subjects
表以进行筛选。在
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())
例如:

>>> reduce(lambda books,s: books.filter(subjects=s),[s1,s2,s3], Book.objects.all())
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` ) 
    INNER JOIN `subjects_book_subjects` T4 ON ( `subjects_book`.`id` = T4.`book_id` ) 
    INNER JOIN `subjects_book_subjects` T6 ON ( `subjects_book`.`id` = T6.`book_id` ) 
    WHERE (
        `subjects_book_subjects`.`subject_id` = 1 
        AND T4.`subject_id` = 2 
        AND T6.`subject_id` = 3
    ) LIMIT 21; args=(1, 2, 3)
[<Book: Book object>]
reduce(lambda books,s:books.filter(subjects=s),[s1,s2,s3],Book.objects.all()) 调试(0.001) 选择'subjects\u book`.'id`、'subjects\u book`.'title`、'subjects\u book`.'subtitle` 来自“主题书” 上的内部联接'subjects\u book\u subjects'('subjects\u book`.'id`='subjects\u book\u subjects`.'book\u id`) 内部联接'subjects\u book\u subjects'T4 ON('subjects\u book`.'id`=T4.'book\u id`) 内部联接'subjects\u book\u subjects'T6 ON('subjects\u book`.'id`=T6.'book\u id`) 在哪里( `主题书主题。`subject\u id`=1 和T4.`subject_id`=2 和T6.`subject_id`=3 )限制21;args=(1,2,3) []
这是一个猜测,但确实是
Book.objects.filter(subjects\uu-in=[2,3,6])
起作用了吗?这显示了所有主题id为2的书籍或主题id为3的书籍或主题id为6的书籍,类似于
Book.objects.filter(subjects\uu-id=2)。filter(subjects\uu-id=3)。filter(subjects\uu-id=6)
?你必须在for循环中添加这些。哇。。它正在工作。我不这么认为。谢谢你,汤姆
>>> reduce(lambda books,s: books.filter(subjects=s),[s1,s2,s3], Book.objects.all())
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` ) 
    INNER JOIN `subjects_book_subjects` T4 ON ( `subjects_book`.`id` = T4.`book_id` ) 
    INNER JOIN `subjects_book_subjects` T6 ON ( `subjects_book`.`id` = T6.`book_id` ) 
    WHERE (
        `subjects_book_subjects`.`subject_id` = 1 
        AND T4.`subject_id` = 2 
        AND T6.`subject_id` = 3
    ) LIMIT 21; args=(1, 2, 3)
[<Book: Book object>]