A common Postgres “gotcha” I’ve run into before is the handling of NULL values. Equality comparisons in Postgres to NULL are neither true nor false.

Consider this data set:

sample_table

idnameboolean_field
1Sample ATrue
2Sample BFalse
3Sample CNULL

In Postgres, if we perform SELECT * FROM sample_table WHERE boolean_field = TRUE;, we’ll get our expected one row.

idnameboolean_field
1Sample ATrue

That translates in Django to SampleTable.objects.filter(boolean_field=True).

Great, we get what we expect!

But now consider SampleTable.objects.all().exclude(boolean_field=True). We’d expect to get the 2nd and 3rd rows right?

Wrong! Django translates that query as SELECT * FROM sample_table WHERE NOT(boolean_field = True);. Since comparisons to NULL values are neither true nor false, this statement only returns the second row.

idnameboolean_field
2Sample BFalse

I wish Django would translate this using the special IS NOT operator.

SELECT * FROM sample_table WHERE boolean_field IS NOT True;

That returns the rows we expect.