Оператор OR в фильтре Django создает дубликаты

когда я печатаю Brand.objects.filter(Q(name__icontains=keyword)|Q(tag__name__icontains=keyword)), выдается два объекта, в отличие от моего ожидания. Должен быть только один.

Мой models.py имеет вид

class Brand(models.Model):
    name = models.CharField(max_length=20)
    tag = models.ManyToManyField('Tag', blank=True)
class Tag(models.Model):
    name = models.CharField(max_length=20)

Когда я печатаю Brand.objects.filter(name__icontains=keyword) и Brand.objects.filter(tag__name__icontains=keyword) по отдельности, каждый из них выдает только один одинаковый объект. Но когда я объединяю эти два запроса, получаются дубликаты. Я обнаружил, что .distinct() решает эту проблему, но я хочу знать почему. Жду помощи!

Не условие or приводит к появлению дубликатов, а тот факт, что вы фильтруете по связанной модели с помощью ManyToManyField. Это означает, что запрос будет выглядеть следующим образом:

SELECT brand.*
FROM brand
LEFT OUTER JOIN brand_tag ON brand_tag.brand_id = brand.id
LEFT OUTER JOIN tag ON tag.id = brand_tag.tag_id
WHERE brand.name LIKE %keyword% OR tag.name LIKE %keyword%

Таким образом, JOIN на модели тегов, и если несколько тегов соответствуют ключевому слову, то эта марка будет повторена столько раз в QuerySet.

Если бы вы таким образом отфильтровали .filter(tag__name__icontains=keyword), вы бы также получили дубликаты.


Примечание: Существует пакет django-taggit [GitHub] для работы с содержимым, содержащим теги. Это может быть лучше, чем реализовывать собственную систему тегов.

Вернуться на верх