ViewSet class variable

Question:

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?

Answers:

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
Answered By: Sunderam Dubey