[Django]-Optimizing djangos count() method

0👍

After browsing through django-rest-framework code I came up with this idea:

  1. Override default Paginator class for a given view:

    class RestaurantList(generics.ListAPIView):
        pagination_class = custom.LimitOffsetPagination
    
  2. Create custom pagination class:

    class LimitOffsetPagination(pagination.LimitOffsetPagination):
        def __init__(self):
            self._countable_queryset = None
            self._was_counted = False
    
        def was_initialized(self):
            return self._countable_queryset is not None
    
        def set_raw_queryset_for_count(self, queryset: QuerySet):
            self._countable_queryset = queryset
    
        def paginate_queryset(self, queryset, request, view=None):
            self.limit = self.get_limit(request)
            if self.limit is None:
                return None
            self.offset = self.get_offset(request)
            self.count = self._countable_queryset.count()
            self.request = request
            if self.count > self.limit and self.template is not None:
                self.display_page_controls = True
            return list(queryset[self.offset:self.offset + self.limit])
    
  3. Override views paginator property:

    @property
    def paginator(self):
        paginator = super().paginator
        if not paginator.was_initialized():
            paginator.set_raw_queryset_for_count(Restaurant.objects.all())
        return paginator
    

Now the count query will look a bit more friendly

SELECT COUNT(*) AS "__count" FROM "restaurants_restaurant"

Leave a comment