I've created a base api view, which extends from APIView, where I log response time, log request, and other common stuffs.
Now, I also want to add request validation here, using the Serializer defined in sub-class Views. I thought the appropriate place is to put that in dispatch() method. But before I call API.dispatch() method, request.data is not prepared. So, that won't work. Can someone help me in right direction as to how to move validation to a single place?
Here's the class structure:
class BaseView(APIView):
    validation_serializer = None
    def dispatch(self, request, *args, **kwargs):
        # Some code here
        # How to use `validation_serializer` here, to validate request data?
        # `request.data` is not available here.
        response = super(BaseView, self).dispatch(request, *args, **kwargs)
        # Some code here
        return response
class MyView(BaseView):
    validation_serializer = ViewValidationSerializer
    def post(self, request, *args, **kwargs):
        pass
I thought another approach could be use decorator on the top of post() method. But if only there was an cleaner way, than putting decorators all across the project?
Note: It's similar to the question here: Django - DRF - dispatch method flow. But as per the suggestion there, I don't want to just copy the entire dispatch method from DRF source code.
The method that processes the django request into a DRF request (and adds the request.data property) is the APIView.initialize_request . The APIView.dispatch() method calls it and then proceeds to call the appropriate method handler (post/patch/put).
You can try to do that yourself by calling it and using the returned object:
class BaseView(APIView):
    validation_serializer = None
    def dispatch(self, request, *args, **kwargs):
        request = self.initialize_request(request, *args, **kwargs)
        kwargs['context'] = self.get_serializer_context()
        serializer = self.validation_serializer(data=request.data, *args, **kwargs)
        # use `raise_exception=True` to raise a ValidationError
        serializer.is_valid(raise_exception=True)
        response = super(BaseView, self).dispatch(request, *args, **kwargs)
        return response
However, I would suggest against this, as other functionality of dispatch() probably should be performed prior to handling validation; thus, you could move the above logic to the relevant post/patch/put methods instead.
In these methods you can also use self.request directly since it was already initialized by dispatch().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With