Django REST Framework: duplicate database queries due to __str__ model method

I am working on a webapp with a Django backend that provides the Django REST Framework API for use by the interface. I recently ran into some performance issues, so I began to study the performance of each of my endpoints - and most of them issue too many queries to the database.

I have a few prefetching questions that I cannot understand, but this (I think) is the easiest. I implemented select_related and prefetch_related , where I can, thanks to the docs, as well as this great post on how to think about impatient downloads.

For one specific model, I have reduced the number of queries decently, but I can’t understand why I still have certain duplicates.

models.py

 class ReadingGroup(models.model): owner = models.ForeignKeyField(settings.AUTH_USER_MODEL) users = models.ManyToManyField(settings.AUTH_USER_MODEL) book_type = models.ForeignKeyField(BookType) .... <other group related fields> def __str__(self): return '%s group: %s' % (self.name, self.book_type) 

serializers.py

 class ReadingGroupSerializer(serializers.ModelSerializer): users = UserSerializer(many = True,read_only=True) owner = UserSerializer(read_only=True) class Meta: model = ReadingGroup fields = ('url', 'id','owner', 'users') @staticmethod def setup_eager_loading(queryset): #select_related for 'to-one' relationships queryset = queryset.select_related('owner') #prefetch_related for 'to-many' relationships queryset = queryset.prefetch_related('users') return queryset 

views.py

 class ReadingGroupViewset(views.ModelViewset): def get_queryset(self): qs = ReadingGroup.objects.all() qs = self.get_serializer_class().setup_eager_loading(qs) return qs 

urls.py

 router.register(r'groups', ReadingGroupViewset) 

The setup_eager_loading() method reduced the number of requests to retrieve all 12 ReadingGroup instances in my database from 40 to 17, with 12 requests being duplicated. Each of the repeated queries is the result of calling the __str__ model method separately for each instance of the model.

I initially thought this was due to something in the DRF docs that assume that the __str__ method is only called for use in the API

The built-in str method of the model will be used to create string representations of the objects used to populate the selection property. These options are used to populate selected HTML inputs in the API.

However, this does not seem to be the case. I applied a workaround for the Django debug toolbar to migrate JSON responses to HTML (since the toolbar only handles HTML responses) ?format=json added to the endpoint request (so the browsed API is being looked up), but duplicate requests are still issued.

Is DRF a call to the __str__ method even though it doesn’t use the lookup API for queries, or is there some other problem with my model?

Could this be related to the behavior associated with using a ModelViewset ? The endpoint I click for this test is simply /api/groups/ , which is one of the URLs automatically generated by the register() command.

EDIT . The comment from @serg below made me think: if it asks for a field that is not part of the serializer, I believe that this will not hurt for prefetching. Adding book_type to setup_eager_loading got rid of duplicate requests:

 @staticmethod def setup_eager_loading(queryset): #select_related for 'to-one' relationships queryset = queryset.select_related('owner') queryset = queryset.select_related('book_type') #prefetch_related for 'to-many' relationships queryset = queryset.prefetch_related('users') return queryset 

I added this field to the code above, so it’s more clear that the __str__ method accessed the relational field.

0
source share

All Articles