Home > front end >  OR operator in Django filter creates duplicates
OR operator in Django filter creates duplicates

Time:02-13

when I print Brand.objects.filter(Q(name__icontains=keyword)|Q(tag__name__icontains=keyword)), it yields two objects as opposed to my expectation. It should be only one.

My models.py is like

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)

When I print Brand.objects.filter(name__icontains=keyword) and Brand.objects.filter(tag__name__icontains=keyword) seperately, each one yields only one same object. But when I merge these two queries, it yields duplicates. I found out .distinct() solves this problem but I wanna know why. Looking forward to help!

CodePudding user response:

It is not the or condition that results in duplicates, it is the fact that you are filtering on a related model with a ManyToManyField. This means that the query will look like:

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%

You thus will JOIN on the tag model, and if multiple tags match the keyword, then that brand will be repeated that many times in the QuerySet.

If you thus would have filtered with .filter(tag__name__icontains=keyword), you would have gotten duplicates as well.


Note: There is a django-taggit package [GitHub] to work with content that contains tags. This might be better than implementing your own tag system.

  • Related