Search code examples
pythondjangodjango-modelsdjango-querysetdjango-orm

Filter object and order by number of filters matched


I have the objects

>>> Post.objects.create(name='First post', tags=['tutorial', 'django', 'example'])
>>> Post.objects.create(name='Second post', tags=['thoughts'])
>>> Post.objects.create(name='Third post', tags=['thoughts', 'django', 'example'])

I want to filter the Post objects to match a series of tags:

>>> filtered = Post.objects.filter(tags__in=['thoughts', 'django', 'example'])

Is there a way to order these results by the number of filters they matched?

Wanted result:

>>> filtered[0]
<Post: Third post>
>>> filtered[1] 
<Post: First post>
>>> filtered[2] 
<Post: Second post>

Actual result:

>>> filtered[0]
<Post: First post>
>>> filtered[1] 
<Post: Second post>
>>> filtered[2] 
<Post: Third post>

I'm using Django 3.2.14


Solution

  • You can annotate with the number of filtered Tag objects:

    from django.db.models import Count
    
    filtered = Post.objects.filter(
        tags__in=['thoughts', 'django', 'example']
    ).alias(
        ntags=Count('tags')
    ).order_by('-ntags')