I have a query that requires to filter exactly 2 authors with the ID
Theoretically,
Book.objects.filter(author__id=1, author__id=2).
New questions are pointing to this one as a duplicate, so here is an updated answer (for one specific backend).
If the backend is Postgres, the SQL you want is (assuming the M2M table is called bookauthor
):
SELECT *
FROM book
WHERE
(SELECT ARRAY_AGG(bookauthor.author_id)
FROM bookauthor
WHERE bookauthor.book_id = book.id) = Array[1, 2];
You can get Django to generate nearly this SQL.
First, pip install django-sql-utils
. Then create this Array
class:
from django.db.models import Func
class Array(Func):
function = 'ARRAY'
template = '%(function)s[%(expressions)s]'
And now you can write your ORM queryset:
from sql_util.utils import SubqueryAggregate
from django.contrib.postgres.aggregates import ArrayAgg
books = Book.objects.annotate(
author_ids=SubqueryAggregate('author__id', Aggregate=ArrayAgg)
).filter(author_ids=Array(1, 2))