Django объединяет запросы AND и OR с полем ManyToMany - PullRequest
0 голосов
/ 03 июня 2011

надеясь, что кто-то может помочь мне с этим.

Я пытаюсь выяснить, могу ли я создать запрос, который позволит мне одновременно извлекать элементы из моей базы данных на основе поля 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

Я хотел бы создать запрос, который извлекает элементы на основе двух критериев:

  1. Элементы, загруженные пользователямичто пользователь следит (называется «бренд» в модели).Так, например, если пользователь следует учетной записи Paramount, я бы хотел, чтобы все элементы, где brand = Paramount.

  2. Элементы, соответствующие ключевым словам в сохраненных поисках.Например, пользователь может сделать и сохранить следующий поиск: «комедия 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/#spanning-multi-valued-relationships)

Заранее спасибо за помощь в этом!

Ответы [ 2 ]

3 голосов
/ 11 июля 2011

После долгих исследований я не смог найти способ объединить это в один запрос, поэтому в итоге я преобразовал свои QuerySets в списки и объединил их.

2 голосов
/ 04 июня 2011

Фильтры Django автоматически AND.Q объекты необходимы, только если вы пытаетесь добавить OR.Кроме того, фильтр запросов __in поможет вам много.

Если у пользователей есть несколько брендов, которые им нравятся, и вы хотите вернуть любой бренд, который вам нравится, вы должны использовать:

`brand__in=brands`

Где brands - это набор запросов, возвращаемый чем-то вроде someuser.brands.all().

То же самое можно использовать для параметров поиска:

`tags__name__in=['80s','comedy']`

, который будет возвращать вещи, отмеченные как '80s'или «комедия».Если вам нужны оба (вещи, помеченные как '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().Имеет больше смысла.

...