In Django Rest Framework, I have two separate views for the same model. I would like to use the same url pattern to access both views, and differentiate between the two based on the method that is used. So I have something like:
class MyObjectListAPIView(generics.ListAPIView):
pass
class MyObjectCreateAPIView(generics.CreateAPIView):
pass
Both views obviously would have different logic. The url pattern for both would be 'myObjects\'
, and depending on the method that is used (GET
or POST
), it would need to refer to the appropriate view (MyObjectListAPIView
or MyObjectCreateAPIView
respectively). Is there a way to achieve this (without reverting to plain Django and losing the functionality of DRF)?
Short Answer:
The out-of-the-box way to achieve this is with ViewSets
, specifically the ModelViewSet
, in conjunction with the default ModelSerializer
and DRF's built-in DefaultRouter
. It would look like the below:
## views.py ##
from rest_framework import viewsets
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer
class MyObjectViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
## urls.py ##
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import MyObjectViewSet
router = DefaultRouter()
router.register(r'myObjects', MyObjectViewSet)
urlpatterns = [
path('', include(router.urls)),
]
Note, this will achieve what you want, i.e. same endpoint 'myObjects/' with different logic based on HTTP Method (GET -> List, POST -> Create) -- BUT note that it will also do more than just this, as you will also get the associated Retrieve/Update/Delete functionality at the endpoint 'myObjects/<pk>/'.
Longer Answer:
If you want to avoid ViewSets
for any particular reason, you would just use the GenericAPIView
with the ListModelMixin
and CreateModelMixin
as well. This could look something like the below:
## views.py ##
from rest_framework import generics, mixins
from myapp.models import MyModel
from myapp.serializers import MyModelSerializer
class MyObjectListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin,
generics.GenericAPIView):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
Then simply register it to your URLs file as you normally would for any Class-Based View, with no need for the Router here; e.g. like the below:
## urls.py ##
from django.urls import path
from .views import MyObjectListCreateAPIView
urlpatterns = [
# ..any other url patterns.. #
path('myObjects/', MyObjectListCreateAPIView.as_view())
]
This should satisfy your constraints exactly, without the additional features the ViewSet
offers.
The official DRF docs do a very good step-by-step tutorial on how to move from 'APIView' to 'GenericViews' plus 'Mixins', all the way through to 'ViewSets with Routers', and the docs are pretty comprehensive. I recommend taking a look at it here if you haven't already.