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?
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.
In Django, select_related and prefetch_related are designed to stop the deluge of database queries that are caused by accessing related objects.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With