[Django]-Django: how to filter on subset of many-to-many field?

0👍

This question might be old but I have not found any built-in solution in django (like __in filter tag)

So to keep your example. We have M2M relationship between Article and Tags and want to get all articles which have the given tags, A,B,C.
There is no straightforward solution in Django and we have to think back to SQL(do not worry, we still can do everything in Django ORM)
In M2M relationship there needs to be a common table which connects the both relations. Let’s call it TagArticle. A row in this table is just a tag and an article ids.

What we effectively have to do is this:

1) Filter the common TagsArticle table to get only the rows with the A,B, or C tags.

2) Group the found rows by the Article and count the rows.

3) Filter out all rows where the count is smaller then the number of tags(3 in our example)

4) Now join or filter the Article table with the previous result

Fortunately, we do not have to access the TagArticle table directly in Django. The pseudo code is then:

 from django.db.models import Count
 ...
  tags = ['A', 'B', 'C']
  articleQS = Tag.objects.filter(name__in=tags).values('article')
  .annotate(tagCount=Count('article'))
            .filter(catCount=len(tags)).values('article')

        articles = Article.objects.filter(id__in=articleQS)

-1👍

Let’s say Tag is:

class Tag(models.model):
   article = models.ForeignKey('Article')
   name = models.CharField(max_length=2)

Then I think you can do:

a_ids = Tag.objects.filter(name='A').values_list('article_id')
b_ids = Tag.objects.filter(name='B').values_list('article_id')
Article.objects.filter(id__in=a_ids).filter(id__in=b_ids)
👤eran

Leave a comment