Refactoring to use ViewSets

Let's take our current set of views, and refactor them into view sets.

First of all let's refactor our UserList and UserDetail views into a single UserViewSet. We can remove the two views, and replace them with a single class:

  1. from rest_framework import viewsets
  2. class UserViewSet(viewsets.ReadOnlyModelViewSet):
  3. """
  4. This viewset automatically provides `list` and `detail` actions.
  5. """
  6. queryset = User.objects.all()
  7. serializer_class = UserSerializer

Here we've used the ReadOnlyModelViewSet class to automatically provide the default 'read-only' operations. We're still setting the queryset and serializer_class attributes exactly as we did when we were using regular views, but we no longer need to provide the same information to two separate classes.

Next we're going to replace the SnippetList, SnippetDetail and SnippetHighlight view classes. We can remove the three views, and again replace them with a single class.

  1. from rest_framework.decorators import action
  2. from rest_framework.response import Response
  3. class SnippetViewSet(viewsets.ModelViewSet):
  4. """
  5. This viewset automatically provides `list`, `create`, `retrieve`,
  6. `update` and `destroy` actions.
  7. Additionally we also provide an extra `highlight` action.
  8. """
  9. queryset = Snippet.objects.all()
  10. serializer_class = SnippetSerializer
  11. permission_classes = [permissions.IsAuthenticatedOrReadOnly,
  12. IsOwnerOrReadOnly]
  13. @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
  14. def highlight(self, request, *args, **kwargs):
  15. snippet = self.get_object()
  16. return Response(snippet.highlighted)
  17. def perform_create(self, serializer):
  18. serializer.save(owner=self.request.user)

This time we've used the ModelViewSet class in order to get the complete set of default read and write operations.

Notice that we've also used the @action decorator to create a custom action, named highlight. This decorator can be used to add any custom endpoints that don't fit into the standard create/update/delete style.

Custom actions which use the @action decorator will respond to GET requests by default. We can use the methods argument if we wanted an action that responded to POST requests.

The URLs for custom actions by default depend on the method name itself. If you want to change the way url should be constructed, you can include url_path as a decorator keyword argument.