Django объединяет запросы AND и OR с полем ManyToMany
Надеясь, что кто-то может помочь мне с этим.
Я пытаюсь выяснить, могу ли я создать запрос, который позволит мне получать элементы из моей базы данных на основе поля ForeignKey и ManyToManyField одновременно. Сложной частью является то, что ему нужно будет фильтровать несколько объектов ManyToMany.
Надеюсь, пример прояснит это. Вот мои (упрощенные) модели:
class Item(models.Model):
name = models.CharField(max_length=200)
brand = models.ForeignKey(User, related_name='brand')
tags = models.ManyToManyField(Tag, blank=True, null=True)
def __unicode__(self):
return self.name
class Meta:
ordering = ['-id']
class Tag(models.Model):
name = models.CharField(max_length=64, unique=True)
def __unicode__(self):
return self.name
Я хотел бы создать запрос, который получает элементы на основе двух критериев:
Элементы, загруженные пользователями, за которыми следит пользователь (в модели это называется "бренд"). Так, например, если пользователь следует учетной записи Paramount, я бы хотел, чтобы все элементы, где brand = Paramount.
Элементы, соответствующие ключевым словам в сохраненных поисках. Например, пользователь может сделать и сохранить следующий поиск: "комедия 80-х". В этом случае я хотел бы, чтобы все элементы, в которых теги содержали и "80-е", и "комедию".
Теперь я знаю, как построить запрос для каждого независимо. Для #1 это:
items = Item.objects.filter(brand=brand)
И для № 2 (на основе документов):
items = Item.objects.filter(tags__name='80s').filter(tags__name='comedy')
Мой вопрос: возможно ли сконструировать это как один запрос, чтобы мне не приходилось преобразовывать каждый запрос в список, объединять их и удалять дубликаты?
Похоже, проблема в том, что нет способа использовать объекты Q для создания запросов, где вам нужно много-многозначное поле элемента (в данном случае теги), чтобы соответствовать нескольким значениям. Следующий запрос:
items = Item.objects.filter(Q(tags__name='80s') & Q(tags__name='comedy'))
не работает.
(См.: https://docs.djangoproject.com/en/dev/topics/db/queries/)
Заранее спасибо за вашу помощь в этом!
2 ответа
После долгих исследований я не смог найти способ объединить это в один запрос, поэтому я закончил преобразование моих QuerySets в списки и их объединение.
Фильтры Джанго автоматически AND. Q
объекты нужны только если вы пытаетесь добавить OR. Так же __in
Фильтр запросов поможет вам много.
Предполагая, что у пользователей есть несколько брендов, которые им нравятся, и вы хотите вернуть любой бренд, который им нравится, вы должны использовать:
`brand__in=brands`
куда brands
это набор запросов, возвращаемый чем-то вроде someuser.brands.all()
,
То же самое можно использовать для параметров поиска:
`tags__name__in=['80s','comedy']`
Это вернет вещи с тегами "80-х" или "комедия". Если вам нужны оба (вещи, отмеченные как "80-е", так и "комедия"), вам придется передать каждый из них в последовательный фильтр:
keywords = ['80s','comedy']
for keyword in keywords:
qs = qs.filter(tags__name=keyword)
PS related_name
значения всегда должны указывать противоположные отношения. У вас будут логические проблемы с тем, как вы это делаете в настоящее время. Например:
brand = models.ForeignKey(User, related_name='brand')
Значит это somebrand.brand.all()
на самом деле вернется Item
объекты. Так должно быть:
brand = models.ForeignKey(User, related_name='items')
Затем вы можете получить товары бренда с somebrand.items.all()
, Имеет гораздо больше смысла.