Django queryset EXCLUDE: are these equivalent?

Viewed 57

In Django, are these two equivalent?

Cars.objects.exclude(brand='mercedes').exclude(year__lte=2000)

and

Cars.objects.exclude(brand='mercedes', year__lte=2000)

?

I know the first one says: exclude any mercedes and exclude any car older than year 2000. What about the second one? Does it say the same? Or it does only exclude the combination of mercedes being older than year 2000?

Thanks!

1 Answers

The two are not equivalent.

As is specified in the documentation on exclude(..):

The lookup parameters (**kwargs) should be in the format described in Field lookups below. Multiple parameters are joined via AND in the underlying SQL statement, and the whole thing is enclosed in a NOT().

So the first query can be read as:

-- first query
SELECT car.*
FROM car
WHERE NOT (brand = 'mercedes') AND NOT (YEAR <= 2000)

whereas the latter is equivalent to:

-- second query
SELECT car.*
FROM car
WHERE NOT (brand = 'mercedes' AND YEAR <= 2000)

The first query this is semantically the same as "All cars that are not a Mercedes; and that are not build before or in the year 2000". Whereas the second query is "All cars except Mercedeses that are built before or in the year 2000.".

So in case the table contains a Ford that is built in 1993, then the first query will not include it, whereas the second will, since the brand is not Mercedes, it is not excluded (so it will be part of the queryset).

Related