简体   繁体   中英

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()

There are different usages for get_queryset and self.queryset eg 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).

The gist of what get_queryset method in viewsets is doing is something along the lines of

def get_queryset(self):
    return self.queryset

Since you have overridden the get_queryset method and calling super , you're altering the result.

This probably won't be useful for anyone else, but for completeness I'm answering it.

Indeed both the queryset and get_queryset querysets get combined. It looks like the get_queryset call to super(FeedbackFieldViewSet, self).get_queryset() gets the queryset value ( CustomField.objects.all() ) and then the list(chain(queryset, FeedBackField,objects.all())) is what combines the two querysets.

My bug was to do with paging, ie the missing values were missing because they weren't on the first page of results.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM