Как получить содержимое ответа из объекта Response() в декораторе представления?
Допустим, у меня есть декоратор, который может быть применен к представлению, основанному на классе DRF. Базовая версия декоратора выглядит следующим образом:-
`class LogRequest:
def __init__(self, log_success=True, methods_to_log=None):
self.log_success = log_success
self.methods_to_log = methods_to_log if methods_to_log is not None else ["post"]
def __call__(self, view_class):
view_class.methods_to_log = self.methods_to_log
view_class.log_success = self.log_success
for method_name in self.methods_to_log:
if hasattr(view_class, method_name):
method = getattr(view_class, method_name)
decorated_method = self.wrap_method(method)
setattr(view_class, method_name, decorated_method)
return view_class
def wrap_method(self, method):
@wraps(method)
def wrapped_method(self, request, *args, **kwargs):
method_name = request.method.lower()
if method_name in getattr(self, "methods_to_log", []):
log = Log(path=request.path, method=method_name)
log.request_body = Log.parse_request_body(request)
try:
response = method(self, request, *args, **kwargs)
except Exception as e:
tb = traceback.format_exc()
log.error_traceback = tb
log.status_code = 500
log.response_body = str(e)
log.save()
return JsonResponse({"error": str(e)}, status=500)
if self.log_success or response.status_code >= 400:
log.status_code = response.status_code
if 'application/json' in response.get('Content-Type', ''):
response_content = response.rendered_content.decode("utf-8")
log.response_body = response_content
log.save()
return response
return method(self, request, *args, **kwargs)
return wrapped_method`
Декоратор применяется к классу представления следующим образом:-
`@LogRequest(log_success = True,methods_to_log=["post","get"])
class TestDecoView(generics.GenericAPIView):
permission_classes = (AllowAny,)
def post(self,request,*args, **kwargs):
return JsonResponse({"message":"OK"},status=403)
def get(self,request,*args, **kwargs):
raise Exception("HAHA")`
Проблема в том, что когда log_success равен true и я хочу регистрировать успешные ответы или 400 ошибок, я получаю ошибки типа JsonResponse' object has no attribute 'rendered_content' or 'Response' object has no attribute 'rendered_content' depending on what kind of response I am sending.
Исключения регистрируются отлично, остальное - нет. Есть идеи, как это исправить?
Я попробовал установить accepted_renderer вручную, и это не дает ошибки. Но при этом содержимое ответа сохраняется в виде пустой строки. Есть идеи, как это исправить?
Вы столкнулись с этой проблемой в основном потому, что JsonResponse и Django REST Framworks объекты ответа, действуют совершенно по-разному в плане рендеринга содержимого ответа.
Если говорить конкретно об объекте DRF Response, то rendered_content является хорошим вариантом, он заполняется только после того, как ответ отображается. Для JsonResponse этот атрибут отсутствует, что приводит к ошибкам.
Короче говоря, используйте render, чтобы убедиться, что содержимое доступно, прежде чем получить к нему доступ, а также помните, что вызывать "response.render()" и для "JsonResponse" использовать "json.dumps(response.content)" напрямую.
Я переписал ваш код и отметил следующее:
def wrap_method(self, method):
@wraps(method)
def wrapped_method(self, request, *args, **kwargs):
method_name = request.method.lower()
if method_name in getattr(self, "methods_to_log", []):
log = Log(path=request.path, method=method_name)
log.request_body = Log.parse_request_body(request)
try:
response = method(self, request, *args, **kwargs)
except Exception as e:
tb = traceback.format_exc()
log.error_traceback = tb
log.status_code = 500
log.response_body = str(e)
log.save()
return JsonResponse({"error": str(e)}, status=500)
if isinstance(response, Response):
response.render()
if self.log_success or response.status_code >= 400:
log.status_code = response.status_code
if isinstance(response, JsonResponse):
log.response_body = response.content.decode("utf-8")
elif isinstance(response, Response) and 'application/json' in response.get('Content-Type', ''):
log.response_body = response.rendered_content.decode("utf-8")
log.save()
return response
return method(self, request, *args, **kwargs)
return wrapped_method
Надеюсь, ваш вопрос уже решен, если у вас возникнут какие-либо трудности, дайте мне знать.