Django Rest Framework:Return 来自 mixin 的 dispatch 方法的响应
Django Rest Framework: Return response from mixin's dispatch method
为了与 slack 交互,服务器需要能够基于一些加密散列来验证请求。如果此检查 returns 为假,服务器应以 400 响应。将此作为混入似乎是明智的:
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
这给出了错误 "accepted_renderer not set on Response"
基于 SO 问题,我添加了以下内容:
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
response = Response(status=status.HTTP_400_BAD_REQUEST)
response.accepted_renderer = JSONRenderer
response.accepted_media_type = "application/json"
response.renderer_context = {}
return response
但这给出了错误:AttributeError: 'NoneType' object has no attribute 'get_indent'
为什么它需要一个 accepted_renderer,因为它只响应 HTTP 状态代码,没有其他数据?解决这个问题的最简单方法是什么?
回答中的以下建议使 EmptyResponse 对象继承自 Response:
Traceback (most recent call last):
File "path/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "path/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "path/lib/python3.8/site-packages/django/middleware/common.py", line 106, in process_response
if response.status_code == 404:
AttributeError: 'dict' object has no attribute 'status_code'
创建一个渲染器,returns 似乎没有什么可以让它工作。如果这是 'correct' 方式,我会感到惊讶,但它完成了工作。
class NoneRenderer(BaseRenderer):
def render(self, *args, **kwargs):
return {}
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
response = Response(status=status.HTTP_400_BAD_REQUEST)
response.accepted_renderer = NoneRenderer
response.accepted_media_type = "*/*"
response.renderer_context = {}
return response
一开始的解决方法:你的第二种方法没问题,只需要实例化JSONResponse
class即可(DRF在views.APIView
的get_renderers
方法中实现):
response.accepted_renderer = JSONRenderer()
背景:
- Django
WSGIHandler
(继承自Basehandler
)调用response.render()
渲染响应
- DRF
Response
(继承自 SimpleTemplateResponse
)对象有一个 render
方法,通过 rendered_content
属性(它调用render
具有传递数据、媒体类型和上下文的渲染器方法)
- 在最初的content-negotiation阶段,根据
DEFAULT_RENDERER_CLASSES
/APIView.renderer_classes
设置和client传递的Aceept
header来设置renderer;所选渲染器在 HttpRequest
对象中设置为 accepted_renderer
,媒体类型设置为 request.accepted_media_type
属性
- 如果渲染器需要任何额外的上下文,
Response
对象也需要 renderer_context
属性;例如,views.APIView
将当前视图、请求和参数设置为 renderer_context
dict
现在应该清楚为什么您需要 Response
对象的属性 -- 获取渲染器、媒体类型并传递所选渲染器可能需要的任何额外上下文。
,您在其中设置上述属性,然后从渲染器 returning 一个空的字典作为响应。如果你想遵循这条路线,一个更简单和更清晰的选择是从 render
方法创建一个 Response
的 subclass 和 return 一个空字典,例如:
class EmptyResponse(rest_framework.response.Response):
def render(self):
# You can have your own rendered content here
self.content = b''
return self
现在只需要 returning EmptyResponse
对象即可,无需添加渲染器相关属性:
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
return EmptyResponse(status=status.HTTP_400_BAD_REQUEST)
现在,除非您要添加一些自定义内容,否则不需要延迟呈现;你可以直接 return HttpResponse
object:
from django.http import HttpResponse
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
如果需要,您可以在初始化 HttpResponse
时传递 content
(以字节为单位)。但如果由于某种原因,需要惰性渲染,则需要使用Response.render
.
为了与 slack 交互,服务器需要能够基于一些加密散列来验证请求。如果此检查 returns 为假,服务器应以 400 响应。将此作为混入似乎是明智的:
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
这给出了错误 "accepted_renderer not set on Response" 基于 SO 问题,我添加了以下内容:
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
response = Response(status=status.HTTP_400_BAD_REQUEST)
response.accepted_renderer = JSONRenderer
response.accepted_media_type = "application/json"
response.renderer_context = {}
return response
但这给出了错误:AttributeError: 'NoneType' object has no attribute 'get_indent'
为什么它需要一个 accepted_renderer,因为它只响应 HTTP 状态代码,没有其他数据?解决这个问题的最简单方法是什么?
回答中的以下建议使 EmptyResponse 对象继承自 Response:
Traceback (most recent call last):
File "path/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "path/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "path/lib/python3.8/site-packages/django/middleware/common.py", line 106, in process_response
if response.status_code == 404:
AttributeError: 'dict' object has no attribute 'status_code'
创建一个渲染器,returns 似乎没有什么可以让它工作。如果这是 'correct' 方式,我会感到惊讶,但它完成了工作。
class NoneRenderer(BaseRenderer):
def render(self, *args, **kwargs):
return {}
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
response = Response(status=status.HTTP_400_BAD_REQUEST)
response.accepted_renderer = NoneRenderer
response.accepted_media_type = "*/*"
response.renderer_context = {}
return response
一开始的解决方法:你的第二种方法没问题,只需要实例化JSONResponse
class即可(DRF在views.APIView
的get_renderers
方法中实现):
response.accepted_renderer = JSONRenderer()
背景:
- Django
WSGIHandler
(继承自Basehandler
)调用response.render()
渲染响应 - DRF
Response
(继承自SimpleTemplateResponse
)对象有一个render
方法,通过rendered_content
属性(它调用render
具有传递数据、媒体类型和上下文的渲染器方法) - 在最初的content-negotiation阶段,根据
DEFAULT_RENDERER_CLASSES
/APIView.renderer_classes
设置和client传递的Aceept
header来设置renderer;所选渲染器在HttpRequest
对象中设置为accepted_renderer
,媒体类型设置为request.accepted_media_type
属性 - 如果渲染器需要任何额外的上下文,
Response
对象也需要renderer_context
属性;例如,views.APIView
将当前视图、请求和参数设置为renderer_context
dict
现在应该清楚为什么您需要 Response
对象的属性 -- 获取渲染器、媒体类型并传递所选渲染器可能需要的任何额外上下文。
render
方法创建一个 Response
的 subclass 和 return 一个空字典,例如:
class EmptyResponse(rest_framework.response.Response):
def render(self):
# You can have your own rendered content here
self.content = b''
return self
现在只需要 returning EmptyResponse
对象即可,无需添加渲染器相关属性:
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
return EmptyResponse(status=status.HTTP_400_BAD_REQUEST)
现在,除非您要添加一些自定义内容,否则不需要延迟呈现;你可以直接 return HttpResponse
object:
from django.http import HttpResponse
class SlackValidationMixin:
def dispatch(self, request, *args, **kwargs):
if validate_slack_request(request):
return super().dispatch(request, *args, **kwargs)
else:
return HttpResponse(status=status.HTTP_400_BAD_REQUEST)
如果需要,您可以在初始化 HttpResponse
时传递 content
(以字节为单位)。但如果由于某种原因,需要惰性渲染,则需要使用Response.render
.