I have two models
class Tag(models.Model):
key = models.CharField(max_length=200)
class Post(models.Model):
name = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag)
I m trying to filter out posts with a list of tags. Lets say tags heat
and warm
. I will get a list of tags in my api function(['heat', 'warm']
). I want to filter all Post data which have tags whose keys are in the list. I tried many types and didn't get correct output. Is there a way to do this on single query?
All Post with this tag key equal to heat
or warm
Post.objects.filter(tags__key_in=['heat', 'warm'])
Add distinct to avoid duplicate :
Post.objects.filter(tags__key_in=['heat', 'warm']).distinct()
While Wilfried's answer is correct and perfectly fine for a lot of use cases, it's worth noting that on the SQL level, DISTINCT
may have a performance impact, especially if you expect you query to match a significant portion of your data (depending on DB and table sizes; see e.g. here and here for more details).
Another slightly more verbose option, which avoids this pitfall, is using a through
model and a Subquery
(introduced in django 1.11). Based on OPs code:
class Tag(models.Model):
key = models.CharField(max_length=200)
class Post(models.Model):
name = models.CharField(max_length=200)
tags = models.ManyToManyField(Tag, through='Tagging')
class Tagging(models.Model):
tag = models.ForeignKey(Tag, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
and the respective query:
tags = Tagging.objects.filter(tag__key__in=['heat', 'warm'])
Post.objects.filter(pk__in=models.Subquery(tags.values('post__pk')))
Using .explain(analyze=True)
(introduced in django 2.1) will help you make an informed decision.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With