'Why does a Django foreign key id __in query fail to match None?

When filtering a queryset on a nullable foreign key, I can filter by an ID value (foo_id=123) or by None (foo_id=None). However, if I attempt to filter by a list (foo_id__in=[123, None]) the None is ignored.

Why is this happening, and what is the best workaround for filtering on a foreign key using a list which includes None?

Example:

from django.db import models

class Foo(models.Model):
  name = models.CharField(max_length=100)

class Bar(models.Model):
  foo = models.ForeignKey(Foo, on_delete=models.PROTECT,
                          blank=True, null=True)
foo = Foo.objects.create(name='myfoo')
Bar.objects.create(foo=foo)
Bar.objects.create(foo=None)

Bar.objects.count()                                    # 2
Bar.objects.filter(foo_id=foo.id).count()              # 1
Bar.objects.filter(foo_id=None).count()                # 1
Bar.objects.filter(foo_id__in=[foo.id, None]).count()  # 1 - Expected 2!


Solution 1:[1]

I don't know why the None in foo_id__in=[123, None] is ignored, but the best workaround I've come up with is the following:

Bar.objects.filter(Q(foo_id=foo.id) | Q(foo_id=None)).count()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Wesley