1

I have a database relationship like the following:

  +-----------+
  | Container |
  +-----------+
  | id        |
  +-----------+
        | 
        |1..n 
+--------------+
| Child        |
+--------------+
| id           |
| container_id |
+--------------+

I want to nest the serializers for the Child in the Container serializer so I can get both objects in one HTTP request. However, when I query for a list of Containers, Django REST Framework does a single query to get all the Containers, but then does a bunch of individual queries for each set of Child objects associated with a specific Container object. Here is my toy example:

# Models
class Container(models.Model):
    pass

class Child(models.Model):
    container = models.ForeignKey(Container,related_name="children")

# Serializers
class ChildSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Child
        fields = ('url','container')

class ContainerSerializer(serializers.HyperlinkedModelSerializer):
    children = ChildSerializer(many=True)
    class Meta:
        model = Container
        fields = ('url','children')

# Views
class ContainerViewSet(viewsets.ModelViewSet)
    queryset = Container.objects.all()
    serializer_class = ContainerSerializer

class ChildViewSet(viewsets.ModelViewSet)
    queryset = Child.objects.all()
    serializer_class = ChildSerializer

Is there a way to coalesce all the Child queries into one backend query and then distribute the results amongst the Container objects?

Kevin Brown-Silva
  • 40,873
  • 40
  • 203
  • 237
Ross Rogers
  • 23,523
  • 27
  • 108
  • 164

1 Answers1

1

Django REST Framework will not optimize your queries for you, it's up to you to decide how best to remove any N+1 queries. You should follow the guidelines covered in the Django documentation to handle performance issues.

In the case of ForeignKey relationships, you should use select_related in your query, which will pre-fetch the objects in the original query.

In the case of ManyToMany and GenericForeignKey relationships, you should use prefetch_related. I've written quite a bit about this in another Stack Overflow answer, but the gist is that you use it similar to select_related.

You should override the query in get_queryset on the view for best results, as you don't need to worry about Django REST Framework incorrectly cloning the queryset when used as an attribute on the class.

Community
  • 1
  • 1
Kevin Brown-Silva
  • 40,873
  • 40
  • 203
  • 237