Search code examples
pythondjangodjango-rest-frameworkdjango-querysetdjango-viewsets

ViewSet class variable


Now I have the following logic implemented for a GET request in Django Rest Framework:

class SomeViewSet(mixins.ListModelMixin,
                  GenericViewSet):
    count = None

    def get_queryset(self):
        query_set = ... # some_logic
        self.count = query_set.count()
        return query_set

    def list(self, request, *args, **kwargs):
        response = super().list(request, *args, **kwargs)
        response.data = {'count': self.count,
                         'data': response.data}
        return response

That is, the queryset is calculated according to complex logic, and it may contain a different number of objects that need to be returned in a GET request, since I don’t have access to the query_set variable inside the list function and I don’t want to copy the query_set calculation logic, I decided do it with a class variable.

But still, the feeling that this is not very correct does not leave. What other options are there?


Solution

  • You can use self.get_queryset() inside the list method instead of using a class variable. The get_queryset method will be executed every time you call it, and it will return the current queryset so:

    class SomeViewSet(mixins.ListModelMixin,
                      GenericViewSet):
    
        def get_queryset(self):
            return ... # some_logic
    
        def list(self, request, *args, **kwargs):
            queryset = self.get_queryset()
            response = super().list(request, *args, **kwargs)
            response.data = {'count': queryset.count(),
                             'data': response.data}
            return response
    

    Edit:

    To avoid the issue of multiple database queries, you can make use of the queryset that is already retrieved by the ListModelMixin and stored in the response.data attribute so:

    class SomeViewSet(mixins.ListModelMixin,
                      GenericViewSet):
    
        def get_queryset(self):
            return ... # some_logic
    
        def list(self, request, *args, **kwargs):
            response = super().list(request, *args, **kwargs)
            queryset = response.data
            response.data = {'count': len(queryset),
                             'data': queryset}
            return response