Django DRF serializer method field on many to many running 2n queries

888 views Asked by At

I'm using Django 2.2 and Django REST Framework.

I have the following model structure

class MyModel(models.Model):
  name = models.ChartField(max_length=200)

class Tag(models.Model):
  name = models.ChartField(max_length=50, unique=True)

class MyModelRelation(models.Model):
  obj = models.ForeignKey(MyModel, related_name='relation')
  user = models.ForeignKey(User)
  tags = models.ManyToManyField(Tag)

  def tag_list(self):
     return self.tags.all().values_list('name', flat=True).distinct()

I want to get the tags list with the MyModel instance and for that, the serializer is

class MyModelSerializer(serializers.ModelSerializer):
  tags_list = serializers.SerializerMethodField(read_only=True)

  def get_tags_list(self, obj):
     return obj.relation.tag_list()

  class Meta:
    fields = [
      'name',
      'tags_list'
    ]

and the view is

class ObjListView(ListAPIView):
  serializer_class = MyModelSerializer
  
  def get_queryset(self):
    return super().get_queryset().select_related('relation').prefetch_related('relation__tags')

But to get 58 records, it is running almost 109 queries.

enter image description here

The my_app_mymodel`, `my_app_mymodelrelation_tags is repeated multiple times

1

There are 1 answers

6
Ken4scholars On

This is how I suggest you solve the problem. Instead of extracting the name in the DB level, you can do it in the serializer level. It will make things way easier and faster. First, remove the tag_list method from the model class. First add the annotation to your views: from django.db.models import F

def get_queryset(self):
    return super().get_queryset().annotate(tags_list=F('relation__tags')).select_related('relation')

Then in your serializers

class MyModelSerializer(serializers.ModelSerializer):
  tags_list = serializers.SlugRelatedField(many=True, slug_field='name', read_only=True)
...