2

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.

nekton
  • 29
  • 1
  • 6

2 Answers2

2

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

Mykyta
  • 160
  • 10
  • This solves it, thanks a ton, applied minor amendments following console output. The use case is simple so GenericAPIView is sufficient. – nekton Jul 21 '20 at 11:35
  • GenericAPIView has queryset, queryset lookup fields, pagination. It is specifically for use with Django models. – Chris Sattinger Jul 01 '23 at 06:24
1

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
K14
  • 181
  • 7
  • Thank you, how does it affect the set up of `router` in __urls.py__? – nekton Jul 21 '20 at 11:29
  • you need to register routers manually like ```urlpatterns = [path('message', APIView.as_view(), name='message'), ]``` – K14 Jul 21 '20 at 19:38