Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I am trying to write a middleware class that ensures that the user is logged in. But the problem is this middleware class will only be applicable to a small set of views and these views return a DRF's Response object rather then the HTTPResponse object and these views are also decorated using api_view.

So when I try to return a Response object from the middle ware class it raises this error.

 assert renderer, ".accepted_renderer not set on Response" AssertionError: .accepted_renderer not set on Response 

I've searched a bit on SO and I guess that the error is somehow related to api_view decorator. But I am confused on how to solve this problem.

Any help is appreciated. :)

like image 676
Adil Malik Avatar asked Jan 28 '15 06:01

Adil Malik


People also ask

Which of the following Middlewares are executed during the response phase?

Again, middleware are run in reverse order during the response phase, which includes process_exception . If an exception middleware returns a response, the process_exception methods of the middleware classes above that middleware won't be called at all.

When you want an interface for returning content negotiated Web API responses you go for?

There's no requirement for you to use the Response class, you can also return regular HttpResponse or StreamingHttpResponse objects from your views if required. Using the Response class simply provides a nicer interface for returning content-negotiated Web API responses, that can be rendered to multiple formats.

What is custom middleware in Django?

Django Middleware is a regular Python class that hooks into Django's request/response cycle. Generally, Django middleware is a plug-and-play system that can be used to modify a request before the Django view processes it or alter the response which is sent back from Django view to the client.

What does status from rest framework is used for?

REST framework includes a set of named constants that you can use to make your code more obvious and readable. The full set of HTTP status codes included in the status module is listed below. The module also includes a set of helper functions for testing if a status code is in a given range.


2 Answers

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!

like image 173
Jordan Avatar answered Sep 21 '22 05:09

Jordan


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) 
like image 36
A. J. Parr Avatar answered Sep 18 '22 05:09

A. J. Parr