Editing response content in Django middleware

django middleware for specific view
process_view middleware django
django middleware takes no arguments
django logging middleware
django 3.0 middleware
django rest framework middleware
django middleware object is not callable
django, httpresponse

I have Django 1.10 project and the following user-defined middleware

class RequestLogMiddleWare(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        response.data['detail'] = 'I have been edited'
        return response

and a REST-endpoint view:

def r_mobile_call_log(request):
    return Response({'success': True, 
                     'detail': 'Before having been edited'}, 
                      status=status.HTTP_200_OK)

So I would expect the final response on client-side to be:

{'success': 'True', 'detail': 'I have been edited'}

However, what I see is:

{'success': 'True', 'detail': 'Before having been edited'}

I put a breakpoint in the middleware's call method to make sure that the function really is executed, and it's ok. response.data["details"] just won't change it's value. Anyone knows what's the reason for this ?

Response is already rendered in the middleware stage so you can't just change response.data, you need to rerender it or change rendered content directly.

class RequestLogMiddleWare(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        if isinstance(response, Response):
            response.data['detail'] = 'I have been edited'
            # you need to change private attribute `_is_render` 
            # to call render second time
            response._is_rendered = False 
            response.render()
        return response

The second approach is to change content directly, but in that case builtin REST Framework browser API will not work because template will not render properly.

import json

class RequestLogMiddleWare(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        if isinstance(response, Response):
            response.data['detail'] = 'I have been edited'
            response.content = json.dumps(response.data)
        return response

source code for render method

Middleware | Django documentation, We will use a python script to modify the body of a response and randomly As you can see, middleware allows you to completely modify the content of a� You can simply modify the response.content string: response.content = response.content.replace("BAD", "GOOD")

I have a feeling that I found cleaner solution. Here's how I rewrote the code:

class RequestLogMiddleWare(object):
    def __init__(self, get_response):
       self.get_response = get_response

    def __call__(self, request):
       response = self.get_response(request)
       return response

    def process_template_response(self, request, response):
       if hasattr(response, 'data'): 
          response.data['detail'] = 'bla-bla-bla'
       return response

Using middleware to modify response payload and status code , You can do this with Django's middleware framework, which is a set of hooks into Django's Here, the processor can modify the content of a response. The django.middleware.gzip.GZipMiddleware compresses content for browsers that understand GZip compression (all modern browsers). This middleware should be placed before any other middleware that need to read or write the response body so that compression happens afterward. It will NOT compress content if any of the following are true:

I don't suggest editing REST-Framework's Response with using middleware. I think you should overload REST-Framework's default JSONRenderer.

Define a custom renderer:

from rest_framework.renderers import JSONRenderer


class CustomJsonRender(JSONRenderer):

    def render(self, data, accepted_media_type=None, renderer_context=None):

        if renderer_context:
            response = renderer_context['response']
            msg = "OK"
            code = response.status_code
            if isinstance(data, dict):
                msg = data.pop('msg', msg)
                code = data.pop('code', code)
                data = data.pop('data', data)
            if code != 200 and data:
                msg = data.pop('detail', 'failed')
            response.status_code = 200
            res = {
                'code': code,
                'msg': msg,
                'data': data,
            }
            return super().render(res, accepted_media_type, renderer_context)
        else:
            return super().render(data, accepted_media_type, renderer_context)

Using it in you APiVIew or ViewSet:

class SimpleView(APIView):
    renderer_classes = (CustomJsonRender,)
    def get(self, request):
        # do something
        return Response({"id":"xx"})

class SimpleViewSet(ModelViewSet):
    renderer_classes = (CustomJsonRender,)
    queryset = SomeModel.objects.all()
    serializer_class = SomeSerializer

You can edit it golbal in settings as well:

REST_FRAMEWORK = {
    "DEFAULT_RENDERER_CLASSES": ("compent.renders.CustomJsonRender",)
}

Then your response has been changed.

Chapter 17: Middleware — Django Book 0.1 documentation, Middleware is a framework of hooks into Django's request/response after the middleware from being able to modify the upload handlers for the request, As a result, middleware can no longer assume that all responses will have a content� Building a Django middleware has been the natural solution. A Django middleware is like a plug-in that you can hook into the Django's request/response cycle. In this post you'll learn how to build your own Django middleware and how to inject data into a view's context directly from the middleware. Setting up the project

Middleware — Django 3.1 documentation, Listing 2-29 Default Django middleware classes in MIDDLEWARE Setting the HTTP Content-Length header for non-streaming responses. If you want to add or modify something in request before it gets turned over to a view method, this is � Request and Response Objects – Django uses request and response objects to pass state through the system. When a page is requested, Django creates an HttpRequest object that contains metadata about the request. Then Django loads the appropriate view, passing the HttpRequest as the first argument to the view function.

Django view method middleware: Built-in middleware classes , They allow us to modify request/response globally. In django 2.0 support for old-style middleware using settings. Permissions and Object level Permissions allow to serve customers based on their access levels or … When the content of the response is explicitly set by assigning response.content. After passing through template response middleware, but before passing through response middleware. </quote> If you are using it in the response middleware, you bypass the third item which usually ensures that the rendering happens.

Understanding middleware functionality in django2.0, However, it can sometimes be beneficial to allow decorators or middleware to modify a response after it has Unlike basic HttpResponse objects, TemplateResponse objects The current rendered value of the response content, using the After passing through template response middleware, but before� On the request and view phases, Django applies middleware in the order given in MIDDLEWARE_CLASSES, and on the response and exception phases, Django applies middleware in reverse order. That is, Django treats MIDDLEWARE_CLASSES as a sort of “wrapper” around the view function: on the request it walks down the list to the view, and on the response it walks back up.

Comments
  • ValueError at ________ Circular reference detected
  • ValueError at ________ Circular reference detected How to resolve this?