Использование values ​​() в отфильтрованном Django QuerySet с полями ManyToMany - PullRequest
0 голосов
/ 18 февраля 2019

У меня есть следующие модели в проекте Django:

class Category(models.Model):
    title = models.CharField(max_length=255)

    def __str__(self):
        return '{} - {}'.format(self.pk, self.title)

class Item(models.Model):
    title = models.CharField(max_length=255)
    categories = models.ManyToManyField(Category)

    def __str__(self):
        return '{} - {}'.format(self.pk, self.title)

Я создал элемент и связал его с двумя категориями:

>>> item1 = Item.objects.get(pk=1)
>>> item1.categories.all()
<QuerySet [<Category: 1 - C1>, <Category: 4 - C4>]>

Я также могу использовать filter ()и получить ожидаемые результаты:

>>> Item.objects.filter(categories__title='C1')
<QuerySet [<Item: 1 - Item1>]>

Однако, когда я использую values ​​() для того же набора запросов, будут возвращены только отфильтрованные отношения:

>>> Item.objects.filter(categories__title='C1').values('categories__title')
<QuerySet [{'categories__title': 'C1'}]>

по сравнению с:

>>> Item.objects.all().values('categories__title')
<QuerySet [{'categories__title': 'C1'}, {'categories__title': 'C4'}]>

Чего мне не хватает?Как я могу получить полный список категорий?

1 Ответ

0 голосов
/ 18 февраля 2019

values не работает таким образом, когда дело касается отношений «многие ко многим».Ваш фильтр фактически создает INNER JOIN в промежуточной таблице (которая отслеживает отношения «многие ко многим»), и values будет применяться после того, как все связанные модели будут отфильтрованы.Из-за этого он не вернет вам все категории для каждого Item объекта, а только отфильтрованные.

Вам следует изменить порядок действий:

Item.objects.values('categories__title').filter(categories__title="C1")

Это на самом деле сначала создаст дополнительное LEFT OUTER JOIN, а затем добавит INNER JOIN для условия фильтрации.

Обратите внимание, что если у вас есть несколько элементов, возвращаемых вашим фильтром, вы получите много дубликатов.значения для заголовков вашей категории, если категории объектов перекрываются.См. Предупреждение в конце этого раздела

...