Django REST Serializer doing N+1 database calls for multiple nested relationship, 3 levels

前端 未结 2 1235
离开以前
离开以前 2021-02-10 06:55

I have a situation where my model has a Foreign Key relationship:

# models.py
class Child(models.Model):
    parent = models.ForeignKey(Parent,)

class Parent(mo         


        
2条回答
  •  一向
    一向 (楼主)
    2021-02-10 07:03

    This question is a bit old but I just came across a very similar problem and managed to reduce the db calls drastically. It seems to me that Django-mptt would make things much easier for you.

    One way would be to define a single model with a ForeignKey to. This way you can find out the hierarchy by it's level in the tree. For example:

    class Person(MPTTModel):
        parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)  
    

    You can find out if the object is a parent by checking if Person.level = 0. If it equals 1, it's a child, 2 grandchild, etc...

    Then, you could modify your code to the following:

    # serializers.py
    class ChildSerializer(serializers.ModelSerializer):
        children = serializers.SerializerMethodField()
    
        def get_children(self, parent):
            queryset = parent.get_children()
            serialized_data = ChildSerializer(queryset, many=True, read_only=True, context=self.context)
            return serialized_data.data
    
    # views.py
    class ParentList(generics.ListAPIView):
    
        def get_queryset(self):
            queryset = cache_tree_children(Person.objects.all())
    

    With this, you'll eliminate your N+1 problem. If you want to add a new ForeignKey to a genre Model, for example, you could simply modify the last line to:

    queryset = cache_tree_children(Person.objects.filter(channel__slug__iexact=channel_slug).select_related('genre'))
    

提交回复
热议问题