The first aspect here is whether the these all produce per se the same query, and the same results. That is not the case for all queries.
Let us begin with two lines that will produce the same query:
instances = Model.objects.filter(Q(a=A) & Q(b=B))
instances = Model.objects.filter(a=A, b=B)
Indeed, both are equivalent, since the .filter(..)
will construct a Q
object based on what you pass. So both end up with a query:
SELECT *
FROM model
WHERE a = a AND b = b
so the exact query. Constructing the query with the ORM is only a matter of some text-processing that is resolved in microseconds, so that will not have much impact on the performance.
It is however a different story if you compare Model.objects.filter(a=A, b=B)
and Model.objects.filter(a=A).filter(b=B)
if a
and b
work with the same model. Indeed, the two consecutive .filter(…)
calls [Django-doc] will make separate joins, not work with the single one. This thus means that the semantics is different, you thus should not look at the performance but what your query is supposed to do, what items it should retrieve.
The same happens with Model.objects.filter(a=A) & Model.objects.filter(b=B)
, here you thus make two queries you eventually intersect, but if the a
and b
are the same, it does not work like a .filter(a=A, b=B)
.
Django does not do the filtering, it just constructs an SQL query to do that, and the database will then process the query. You thus should focus on what you aim to select, less how it is done.