DRF Post to ViewSet without writing into Model

Viewed 3080

I've always written data into database when posting via Django Rest Framework endpoints. This time I would like to process received data and send it somewhere else without writing into DB. I switched from ModelViewSet to ViewSet, I can issue GET request OK but receiving Bad Request 400 when I curl or POST via DRF URL. Here's a working minimal code (removed need for authentication etc):

  • urls.py
from django.urls import path, include
from .views import ContactView
from rest_framework import routers

router = routers.DefaultRouter()
router.register('message', ContactView, basename='message')

urlpatterns = [
    path('', include(router.urls)),
]
  • serializers.py
from rest_framework import serializers

class ContactSerializer(serializers.Serializer):
    text = serializers.CharField(max_length=250)
  • views.py
from rest_framework.response import Response
from .serializers import ContactSerializer
from rest_framework import viewsets

class ContactView(viewsets.ViewSet):
    def list(self, request):
        return Response('Got it')

    def create(self, request):
        serializer = ContactSerializer(data=request.data)
        if serializer.is_valid():
            return Response(serializer.data)
        else:
            return Response('Invalid')

Would greatly appreciate your suggestions.

2 Answers

You can use GenericAPIView for get or post request and do some logic in validate method, for example do something with signals or edit something. Also u can use @detailt_route or @list_route for any ModelViewSet for write special url for instance, example for edit extra data.

how i did rarely:

in urls.py

urlpatterns = [
    url('v1/message', ContactAPIView.as_view(), name='message'),
]

in view.py

class ContactAPIView(GenericAPIView):
    serializer_class = ContactSerializer
    permission_classes = ()

    def post(self, request, *args, **kwargs):
        serializer_class = self.get_serializer_class()
        serializer = serializer_class(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)
        data = {"status": True}

        return Response(data)

in serializers.py

class ContactSerializer(serializers.Serializer):
    text = serializers.TextField()

    def validate(self, attrs):
        write some logic

you are getting this error because you are using Viewsets which uses DefaultRouter to register routers for you. What it does is that it creates 2 urls for your viewset

  1. message
  2. message/id

so in your current case; i.e. viewset you need to send some dummy number in your url to access this post function (which is not a good approach).

So, you should use any class which parent doesn't include ViewSetMixin (which gives functionality of Router Registration) like in your case inherit your view from these classes

  • ListModelMixin
  • CreateModelMixin
  • GenericAPIView
Related