2

I am trying to query all objects in a table without backreferences from another model.

class A(models.Model):
    pass

class B(models.Model):
    reference = models.ForeignKey(A)

In order to get all A objects with no references from any B objects, I do

A.objects.filter(b__isnull=True)

The Django documentation on isnull does not mention backreferences at all.

Can I get into trouble with this or is it just poorly documented?

beruic
  • 5,517
  • 3
  • 35
  • 59
  • 1
    I can't think of a reason where that wouldn't work, [This question](http://stackoverflow.com/q/21405658/1324033) seems to suggest it is correct – Sayse Nov 23 '16 at 14:37

1 Answers1

2

I tried this with Django 1.10.3, using your same code example.

Let's take a look at the raw SQL statement that Django creates:

>>> print(A.objects.filter(b__isnull=True).query)
SELECT "backrefs_a"."id" FROM "backrefs_a" LEFT OUTER JOIN "backrefs_b" ON ("backrefs_a"."id" = "backrefs_b"."reference_id") WHERE "backrefs_b"."id" IS NULL

Technically, this isn't the exact same SQL that Django will send to the database, but it's close enough. For more discussion, see https://stackoverflow.com/a/1074224/5044893

If we pretty it up a bit, you can see that the query is actually quite safe:

SELECT "backrefs_a"."id"
FROM "backrefs_a"
LEFT OUTER JOIN "backrefs_b" ON ("backrefs_a"."id" = "backrefs_b"."reference_id")
WHERE "backrefs_b"."id" IS NULL

The LEFT in the LEFT OUTER JOIN ensures that you will get records from A, even when there are no matching records in B. And, because Django won't save a B with a NULL id, you can rest assured that it will work as you expect.

Community
  • 1
  • 1
John Anderson
  • 484
  • 4
  • 7