Editing response content in Django middleware

2019-06-02 03:18发布

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 ?

2条回答
对你真心纯属浪费
2楼-- · 2019-06-02 03:31

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 just change content directly, but in that case built in 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

查看更多
We Are One
3楼-- · 2019-06-02 03:43

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)

    def process_template_response(self, request, response):
       if hasattr(response, 'data'): 
          response.data['detail'] = 'bla-bla-bla'
       return response
查看更多
登录 后发表回答