Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django ORM: Selecting related set

Tags:

Say I have 2 models:

class Poll(models.Model):     category = models.CharField(u"Category", max_length = 64)     [...]  class Choice(models.Model):     poll = models.ForeignKey(Poll)     [...] 

Given a Poll object, I can query its choices with:

poll.choice_set.all() 

But, is there a utility function to query all choices from a set of Poll?

Actually, I'm looking for something like the following (which is not supported, and I don't seek how it could be):

polls = Poll.objects.filter(category = 'foo').select_related('choice_set') for poll in polls:     print poll.choice_set.all() # this shouldn't perform a SQL query at each iteration 

I made an (ugly) function to help me achieve that:

def qbind(objects, target_name, model, field_name):     objects = list(objects)     objects_dict = dict([(object.id, object) for object in objects])     for foreign in model.objects.filter(**{field_name + '__in': objects_dict.keys()}):         id = getattr(foreign, field_name + '_id')         if id in objects_dict:             object = objects_dict[id]             if hasattr(object, target_name):                 getattr(object, target_name).append(foreign)             else:                 setattr(object, target_name, [foreign])     return objects 

which is used as follow:

polls = Poll.objects.filter(category = 'foo') polls = qbind(polls, 'choices', Choice, 'poll') # Now, each object in polls have a 'choices' member with the list of choices. # This was achieved with 2 SQL queries only. 

Is there something easier already provided by Django? Or at least, a snippet doing the same thing in a better way.

How do you handle this problem usually?

like image 204
Frédéric Jolliton Avatar asked May 12 '09 14:05

Frédéric Jolliton


People also ask

How do you get a related name on Django?

The related_name attribute specifies the name of the reverse relation from the User model back to your model. If you don't specify a related_name, Django automatically creates one using the name of your model with the suffix _set.

What does select related do Django?

In Django, select_related and prefetch_related are designed to stop the deluge of database queries that are caused by accessing related objects.

Why are QuerySets considered lazy?

This is because a Django QuerySet is a lazy object. It contains all of the information it needs to populate itself from the database, but will not actually do so until the information is needed.


1 Answers

Time has passed and this functionality is now available in Django 1.4 with the introduction of the prefetch_related() QuerySet function. This function effectively does what is performed by the suggested qbind function. ie. Two queries are performed and the join occurs in Python land, but now this is handled by the ORM.

The original query request would now become:

polls = Poll.objects.filter(category = 'foo').prefetch_related('choice_set') 

As is shown in the following code sample, the polls QuerySet can be used to obtain all Choice objects per Poll without requiring any further database hits:

for poll in polls:     for choice in poll.choice_set:         print choice 
like image 87
Austin Phillips Avatar answered Oct 10 '22 15:10

Austin Phillips