Django : select_related with ManyToManyField

24,718

Solution 1

Django versions 1.4 and above have prefetch_related for this purpose.

The prefetch_related method is similar to select_related, but does not do a database join. Instead, it executes additional database queries and does the joining in Python.

Solution 2

If you're not on Django 1.4, there's also the django-batch-select library, which works basically the same way as prefetch_related.

Share:
24,718
Paul Tarjan
Author by

Paul Tarjan

I'm a Distinguished Engineer at Robinhood. I used to be the Tech Lead of Developer Productivity at Stripe where I built Sorbet. Before that I was the CTO and cofounder at Trimian. Before that I was a Software Engineer at Facebook on HHVM and the Open Graph. Before that I was the Tech Lead for Yahoo! SearchMonkey. See my homepage for more.

Updated on February 27, 2020

Comments

  • Paul Tarjan
    Paul Tarjan over 4 years

    I have :

    class Award(models.Model) :
        name = models.CharField(max_length=100, db_index=True)
    
    class Alias(models.Model) :
        awards = models.ManyToManyField('Award', through='Achiever')
    
    class Achiever(models.Model):
        award = models.ForeignKey(Award)
        alias = models.ForeignKey(Alias)
        count = models.IntegerField(default=1)
    

    How can I have an Alias which has all its achiever_set and awards prepopulated?

    >>> db.reset_queries()
    >>> Alias.objects.filter(id="450867").select_related("achiever_set__award").get().achiever_set.all()[0].award.name
    u'Perma-Peddle'
    >>> len(db.connection.queries)
    3
    >>> db.reset_queries()
    >>> Alias.objects.filter(id="450867").select_related("awards").get().awards.all()[0].name
    u'Dwarfageddon (10 player)'
    >>> len(db.connection.queries)
    2
    

    I'm going to need a lot of access to the award that an alias has already gotten (both the intermediate table and the awards themselves). How can I batch all of these?