Search code examples
pythondjangodjango-rest-viewsets

What happens if queryset and get_queryset are both defined on a Django ViewSet that inherits from GenericViewSet


I've inherited some Django code and I am struggling to work out what the previous developers have intended with their code.

There is a ViewSet which is configured, which inherits from GenericViewSet. In the class it defines a queryset variable but also defines a get_queryset method. I'm struggling to work out from the docs and tutorials what this even means? What's more interesting is that the get_queryset method returns a queryset of one type, but the queryset variable defines a different type.

What I'm hoping for is for both querysets to be combined (which is the desired behaviour, and which appears to be happening on one server, but not another, so some additional investigation will be needed to work out why)

Code below:

class FeedbackFieldViewSet(NestedViewSetMixin,
                       customer_mixins.CustomerProviderMixin,
                       mixins.ListModelMixin,
                       viewsets.GenericViewSet):
    ##
    # Instantiates and returns the list of permissions required by this viewset.
    #
    # @return The list of permissions.
    #
    def get_permissions(self):
        # Maps action names to tuples of permission classes.
        permissionDict = {
            "list": self.listPermissionClasses,
        }

        if self.action in permissionDict:
            return [permission() for permission in permissionDict[self.action]]

        if self.request.method == "OPTIONS":
            # Anyone can submit an options request
            return []

        raise ProgrammingException("A request with an unknown permission model was received.")

    listPermissionClasses = (IsFeatureEnabled,)

    ##
    # Overrides the get_queryset method to join the custom feedback fields
    # with the default feedback fields.
    #
    def get_queryset(self):
        queryset = super(FeedbackFieldViewSet, self).get_queryset().filter(
            deleted           = False,
            recordContentType = ContentType.objects.get(
                app_label = "hubpro_api",
                model     = "feedback"))

        return list(chain(queryset, FeedbackField.objects.all()))

    serializer_class = FeedbackFieldSerializer
    feature          = "feedback"
    queryset         = CustomField.objects.all()

Solution

  • There are different usages for get_queryset and self.queryset e.g. the definition of self.queryset is used to determine the basename of a view in the router's url definition (see Notes on: http://www.django-rest-framework.org/api-guide/routers/#usage) if you don't provide a queryset as an attribute of the view DRF will raise an error in the router.

    In your specific case (from what your source snippet shows) there is no use for the queryset, if it is not used anywhere else (cannot say for sure based on this snippet)!

    My suggestions for a refactoring to ease the readability and clear things up would be to create a custom method in the queryset for the filter you use in the get_queryset method and I would remove the queryset completely (if its safe depends on the rest of your code) because the next coder will need to dig through the code like you did to understand it.

    Coding is about 80% reading 20% coding and always leave the code better than you found it (~ clean code, robert c. martin).