tags:

views:

61

answers:

1

In example. If I have a model Person who's got a mother field, which is a foreign key.. The following is getting to me:

p = Person.object.get(id=1)
if p.mother_id:
    print "I have a mother!"

In the above example, we've issued one query. I've tricked Django into not fetching the mother by using the _id field instead of mother.id. But if I was to filter on everyone who doesn't have a mother:

Person.objects.filter(mother=None)
Person.objects.filter(mother__id=None)
Person.objects.filter(mother__isnull=True)
Person.objects.filter(mother__id__isnull=True)

All of these join in the related table unnecessarily.. and I can't reference the _id columns, because they're not fields.. so either of the following fails:

Person.objects.filter(mother_id__isnull=True)
Person.objects.filter(mother_id=None)

Is there a way for me to build a querySet that checks the existence of a value in the foreign key column without incurring the join?

Thanks in advance.

Edit (answered): Credit goes to Bernd, who commented on Daniel's answer, but it turns out that this workaround does splendidly for returning people without mothers, without issuing the unnecessary join:

Person.objects.exclude(mother__isnull=False)
+3  A: 

I was surprised by this - I thought Person.object.filter(mother=None) would work without an extra join - but on checking it turns out you're right. In fact this has been logged as a bug in Django's ticket tracker.

Unfortunately, the person who logged it - and who (re)wrote most of the Django query code - is no longer actively contributing to Django, so I don't know when it will actually get fixed. You might try one of the patches on that ticket and see if they help.

Daniel Roseman
Ticket #10790 contains a workaround that appears to work (tested on Django 1.2.3): `Person.objects.exclude(mother__isnull=False)`
Bernd Petersohn
@Daniel - Thanks for finding the bug. Bummer to here that the author isn't active. I may polish and resubmit the patch. I'm pretty passionate about ORMs, and finding Django's a bit lacking.
royal
@Bernd - Brilliant! Thanks. exclude() does the right thing, and I can't think of a case where I would be unable to use that strategy.
royal