Search code examples
pythondjangodjango-modelsdjango-orm

How to use prefetch_related on two M2M values?


I want to prefetch_related to two level of M2M values,

Here is my models.py

class A(models.Model):
    name = models.CharField(max_length=40)
    b = models.ManyToManyField('B')

class B(models.Model):
    name = models.CharField(max_length=40)
    c = models.ManyToManyField('C')

class C(models.Model):
    name = models.CharField(max_length=40)
    d = models.ManyToManyField('D')

And my ORM is

a_obj = A.objects.all().prefetch_related('a__b__c')

And I am trying to access the values like below,

Method A:

for each_obj in a_obj:
    print(each_obj.a__b__c)

Method B:

for each_obj in a_obj:
    print(each_obj.a.all())

Method A throws an error saying No such value a__b__b for A found Method B doesn't throw any error, but the number of queries increases to the length of a_obj.

Is there a way to access a__b__c in a single query?


Solution

  • You load both the related B and C models with .prefetch_related(…) [Django-doc]:

    a_objs = A.objects.prefetch_related('b__c')

    But here .prefetch_related(…) does not change how the items look, it simply loads items. You thus can access these with:

    for a in a_objs:
        for b in a.b.all():
            for c in b.c.all():
                print(f'{a} {b} {c}')
    

    You this still access the items in the same way, but here Django will already load the objects in advance to prevent extra queries.