6.1 ViewSets

ViewSet classes are almost the same thing as View classes, except that they provide operations such as retrieve, or update, and not method handlers such as get or put.

In other word ViewSet class is simply a type of class-based View, that does not provide any method handlers such as .get() or .post(), and instead provides operations/actions such as .list() and .create().

Doc: https://www.django-rest-framework.org/api-guide/viewsets/

View CODE here: https://github.com/amrit94/drf-test/commit/45f6813f67bbf664f2a844b49b903dbf2c14dc83

# Types
* viewsets.ViewSet
* viewsets.ModelViewSet
* viewsets.ReadOnlyModelViewSet
* GenericViewSet
* Custom ViewSet base classes

urls.py

  • If using ViewSet in views –> then create action a/c to views-method
  • If using ModelViewsSet in views –> then all action will work
  • If using ReadOnlyModelViewSet in views –> list and retrieve
# snippets/urls.py
snippet_list = SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
snippet_detail = SnippetViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})
urlpatterns = format_suffix_patterns([
    path('snippet/', snippet_list, name='snippet-list'),
    path('snippet/<int:pk>/', snippet_detail, name='snippet-detail'),
])

6.1.1 viewsets.ViewSet

  • Does not provide any actions by default - No action
  • So, if using ViewSet in views –> then create action a/c to views-method
  • The ViewSet class inherits from APIView

It has no direct advantage over APIView, But if used along with routers, then URLs are auto created.

i.e The API URLs are now determined automatically by the router.

# snippets/views.py
class SnippetViewSet(viewsets.ViewSet):
    def list(self, request):
        queryset = Snippet.objects.all()
        serializer = SnippetSerializer(queryset, many=True)
        return Response(serializer.data)

6.1.2 viewsets.ModelViewSet

  • Automatically provides all actions
    • create(), retrieve(), update(), partial_update(), destroy(), list()
  • The ModelViewSet class inherits from GenericAPIView
# snippets/views.py
class SnippetViewSet(viewsets.ModelViewSet):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

6.1.3 ReadOnlyModelViewSet

  • Automatically provides list and retrieve actions.
  • The ReadOnlyModelViewSet class also inherits from GenericAPIView
# snippets/views.py
class SnippetViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer

6.1.4 GenericViewSet

  • The GenericViewSet class does not provide any actions by default,
    • but does include the base set of generic view behavior, such as
    • the get_object and get_queryset methods.
  • The GenericViewSet class inherits from GenericAPIView

6.2 Routers

Because we’re using ViewSet classes rather than View classes, we actually don't need to design the URL conf ourselves.

URLS can be handled automatically, using a Router class

# Steps
1st --> Create a Router
2nd --> Register router with appropriate viewset

Doc: https://www.django-rest-framework.org/api-guide/routers/

Types

  • SimpleRouter
    • No default API root
  • DefaultRouter
    • This router is similar to SimpleRouter as above, but
    • Additionally includes a default API root view,
    • Or can create own API-root-view
      • by using @api_view
      • views.py and urls.py

snippets/urls.py

# Create Roouter
router = routers.SimpleRouter()

# Register
router.register(r'snippets', SnippetViewSet)

# The API URLs are now determined automatically by the router.
urlpatterns = [
    path('', include(router.urls)),
]

snippets/views.py

Trade-offs between views vs viewsets

Using viewsets can be a really useful abstraction. It helps ensure that URL conventions will be consistent across your API, minimizes the amount of code you need to write, and allows you to concentrate on the interactions and representations your API provides rather than the specifics of the URL conf.

That doesn’t mean it’s always the right approach to take. There’s a similar set of trade-offs to consider as when using class-based views instead of function based views. Using viewsets is less explicit than building your views individually.