Search code examples
pythondjangomany-to-manydjango-queryset

How to do many-to-many Django query to find book with 2 given authors?


I have a query that requires to filter exactly 2 authors with the ID

Theoretically,

Book.objects.filter(author__id=1, author__id=2). 

which is not possible.

How can I solve this problem?

Cheers, Mickey


Solution

  • Not intuitive at first but the answer is right in front of us.

    Book.objects.filter(author__id=1).filter(author__id=2)
    

    If you want an exact match, you could potentially further filter this result by those items that only have exactly 2 authors.

    Book.objects.annotate(count=Count('author')).filter(author__id=1)\
                    .filter(author__id=13).filter(count=2)
    

    If you want exact matches dynamically, how about something like this?:

    def get_exact_match(model_class, m2m_field, ids):
        query = model_class.objects.annotate(count=Count(m2m_field))\
                    .filter(count=len(ids))
        for _id in ids:
            query = query.filter(**{m2m_field: _id})
        return query
    
    matches = get_exact_match(MyModel, 'my_m2m_field', [1, 2, 3, 4])
    
    # matches is still an unevaluated queryset, so you could run more filters
    # without hitting the database.