To elaborate on my comment;
I don't think you'd notice a performance difference. There's far too many other places in the code, stack or event request-response cycle for bottlenecks for =None
vs __isnull
to be a problem.
For a scenario where the bottlenecks of your application were found to be django internals for casting values it would have to be a fine tuned application and infrastructure stack.
To first of all clarify, django turns these two lines in to the exact same SQL query;
MyModel.objects.filter(relationship=None)
MyModel.objects.filter(relationship__isnull=True)
This can be seen in this answer
Now consider the application, where, for the above to be a problem, all of your calls to the database would have to be as fast as possible. All utilising select_related
and prefetch_related
, pulling in only the values which are required for the functionality the queryset is used by.
Within the infrastructure, you'd have to minimise the latency between each service which hosts your application. Then there'd be the network latency between the users of the site and your web servers/CDNs.
The main point being, there are so many possibilities for latency or poor performance outside of django casing None
to Null
.
And to your point about best practice etc, if you were in the habit of writing queries with __isnull
then you can use it's inverse to find objects where data is set and that brings consistency to your code which is key to good code. For example;
has_data = Model.objects.filter(field__isnull=False)
needs_data = Model.objects.filter(field__isnull=True)
To ignore performance, there is a valid reason to use =None
instead of __isnull
however because __isnull
works for null=True
fields where there isn't actually a value in the database. Things like JSONField
may store an empty value, which in JSON terms is null, but in database terms isn't. There's a great concise answer detailing that here.