How to return an rest_framework.response object from a django custom middleware class?

I've just recently hit this problem. This solution doesn't use the Django Rest Framework Response, but if your server just returns JSON this solution might work for you.

New in django 1.7 or greater is the JSONResponse response type.

https://docs.djangoproject.com/en/3.0/ref/request-response/#jsonresponse-objects

In the middleware you can return these responses without having all the "No accepted renderers" and "Response has no attribute encode" errors.

It's very similar format to the DRF Response

The import is as follows: from django.http import JsonResponse

And how you use it:

return JsonResponse({'error': 'Some error'}, status=401)

Hopefully this helps you out!


I've solved this myself by mimicking how rest frameworks views patch the response object with accepted_renderer, accepted_media_type, and renderer_context. In my case I just wanted to return a 401 response using rest frameworks Response class, partly because my tests expect a rest framework response when I call self.client.get(...) and assert response.data.

Other use cases may require you to provide additional info in the renderer_context or use a different accepted_renderer.

from rest_framework import status
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response

class MiddlewareClass(object):

    def __init__(self, get_response):
        self.get_response = get_response

    def unauthorized_response(self, request):
        response = Response(
            {"detail": "This action is not authorized"},
            content_type="application/json",
            status=status.HTTP_401_UNAUTHORIZED,
        )
        response.accepted_renderer = JSONRenderer()
        response.accepted_media_type = "application/json"
        response.renderer_context = {}

        return response

    def __call__(self, request: HttpRequest):
        if not self.authorized(request):
            return self.unauthorized_response(request)
        return self.get_response(request)