Implement HTTP methods in different APIView class in django

I have an API with 2 routes some_resource/ and some_resource/<id> and I would like to implement the normal CRUD actions (list, retrieve, create, update, delete). However, I don't want to use ViewSet because I want to have 1 class for each view. Thus I need to set up the route manually for clarity. :

class SomeResourceRetrieveView(APIView):
  def get(self, request, pk, *args, **kwargs):
    ...

class SomeResourceListView(APIView):
  def get(self, request, *args, **kwargs):
    ...

class SomeResourceCreateView(APIView):
  def post(self, request, *args, **kwargs):
    ...

So in urls.py it looks like this

url_patterns = [
    path("some_resource/", InvitationTeamAccessListAPI.as_view(), name="some-resource-list"),
    path("some_resource/", InvitationTeamAccessCreateAPI.as_view(), name="some-resource-create"),
    path("some_resource/<int:pk>", InvitationTeamAccessRetrieveAPI.as_view(), name="some-resource-retrieve"),
]

However when I use POST on some_resource/, I get a 405. I think django stops at the first matched route and doesn't find an implementation for post. Is there a way to plug all my views to the same pattern but keep them as separate classes?

You can make use of ViewSets

give this a try:

from rest_framework import viewsets
from rest_framework.response import Response

class InvitationTeamAccessViewSet(viewsets.ViewSet):
    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.

    If you're using format suffixes, make sure to also include
    the `format=None` keyword argument for each action.
    """

    def list(self, request):
        # this is your get() method
        queryset = InvitationTeamAccess.objects.all()
        # you should change your serializer name accordingly 
        serializer = InvitationTeamAccessSerializer(queryset, many=True)
        return Response(serializer.data)


    def create(self, request):
        # this is your post method
        # you have to write you post logic here
        pass

    def retrieve(self, request, pk=None):
        # this is your get() details method
        queryset = InvitationTeamAccess.get(pk=pk)
        # you should change your serializer name accordingly 
        serializer = InvitationTeamAccessSerializer(queryset)
        return Response(serializer.data)   

    def update(self, request, pk=None):
        # write your post() method here
        pass

    def partial_update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

and in urls.py

from myapp.views import InvitationTeamAccess
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'some_resource/', InvitationTeamAccess, basename='InvitationTeamAccess')
urlpatterns = router.urls

then with single url path you can perform multiple actions

GET: some_resource/ will show the list of InvitationTeamAccess's
GET: some_resource/1/ will show the detail of a single InvitationTeamAccess
POST: some_resource/ will create new InvitationTeamAccess

also read about ModelVieset

Back to Top