Оператор 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] для работы с содержимым, содержащим теги. Это может быть лучше, чем реализовывать собственную систему тегов.