Search code examples
pythondjangodjango-modelsone-to-manydjango-select-related

Django get dictionary of siblings without using prefetch related?


I have three models like the following and have a list of Boys. How can I get a list of each of their sisters? Unfortunately I can not use prefetch related as I am stuck using a very old version of django.

class Parent(model.Model):
    name = models.CharField(max_length=50)

class Boy(model.Model):
    parent = models.ForeignKey(Parent)
    name = models.CharField(max_length=50)

class Girl(model.Model):
    parent = models.ForeignKey(Parent)
    name = models.CharField(max_length=50)

Desired output would be something like this:

{ boy1: [ sister1, sister2 ], boy2: [ .. ] }

Thanks in advance for any help!


Solution

  • First, get a list of all the parents of the boys, and use that to get all the girls with those parents.

    boys = Boy.objects.all()
    parents = boys.values_list('parent_id', flat=True)
    girls = Girl.objects.filter(parent__in=parents)
    

    Then build a dictionary of girls keyed by parent

    from collections import defaultdict
    girls_by_parent = defaultdict(list)
    for girl in girls:
        girls_by_parent(girl.parent_id) = girl
    

    Then you can build your final dictionary of the sisters for each boy:

    sisters = { boy.pk: girls_by_parent[boy.parent_pk] for boy in boys } 
    

    If you could use prefetch_related, you coyld do something like:

    boys = Boy.objects.select_related('parent').prefetch_related('parent__girl')
    sisters = {b.pk: b.parent.girls_set.all() for b in boys}
    

    Without prefetch_related you'll get extra queries to fetch the girls for every parent.