2

There are two ways to fetch objects which has None in particular column

Book.objects.filter(publication__isnull=True).values('id')

and

Book.objects.filter(publication=None).values('id')

Both results in same query which is

SELECT id from book WHERE publication IS NULL;

So, here I want to check, is there any difference between them from any perspective like "performance", "best practice", "pythonic way" and etc. So that I can decide which one to use.

I have found a related question but answer is not satisfactory

djvg
  • 11,722
  • 5
  • 72
  • 103
SHIVAM JINDAL
  • 2,844
  • 1
  • 17
  • 34
  • 1
    They both result in the exact same query being executed so they are equal. If there was any time difference in execution it'd come from `=None` because that has to be cast to `isnull`. To use `__isnull` in my experience is more common so therefore likely best practice. – markwalker_ Jul 14 '20 at 11:36
  • @markwalker_ yes, but "None" seems more friendly. have you noticed any performance difference? – SHIVAM JINDAL Jul 14 '20 at 11:44
  • 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. – markwalker_ Jul 14 '20 at 12:07
  • @markwalker_ can you elaborate more last line – SHIVAM JINDAL Jul 14 '20 at 12:31

2 Answers2

2

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.

markwalker_
  • 12,078
  • 7
  • 62
  • 99
0

From all I know, both functions are similar in most aspects as they're all native to Django. They differ in one major part though: field==None is NOT reversible while field__isnull=True is.

As an example:

# You can do this ...
queryset = Model.objects.filter(field__isnull=False)

# But you can't do this ...
queryset = Model.objects.filter(field!=None)

# If you insist on the second way ...
queryset = Model.objects.filter.exclude(field=None)

It's an extra step though if you wish to reverse field = None. But for me, all that matters is code uniformity -- if you used one of these before, it's better to use the same function again as people don't have to look similar things up multiple times.

EDIT

I looked up both of these in Django's Queryset documentation. I was able to see isnull on the side navigation bar but not None, so it seems like isnull will be a better practice.

crimsonpython24
  • 2,223
  • 2
  • 11
  • 27