Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to resist unnecessary joins that are only checking id existence when using Django's orm?

Tags:

python

django

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)

Edit (more detail):

I should also mention that I've found this behavior actually only seems to rear it's head when the FK relationship is nullable. Odd, but true.

like image 439
royal Avatar asked Oct 21 '10 22:10

royal


People also ask

What is PK in Django?

pk is short for primary key, which is a unique identifier for each record in a database. Every Django model has a field which serves as its primary key, and whatever other name it has, it can also be referred to as "pk".

What is Django ORM?

One of the most powerful features of Django is its Object-Relational Mapper (ORM), which enables you to interact with your database, like you would with SQL. In fact, Django's ORM is just a pythonical way to create SQL to query and manipulate your database and get results in a pythonic fashion.


1 Answers

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.

like image 85
Daniel Roseman Avatar answered Oct 19 '22 08:10

Daniel Roseman