[英]DRF APIView move request validation to dispatch method using request.data
我已经创建了一个基本api视图,它从APIView
扩展,在那里我记录响应时间,日志请求和其他常见的东西。
现在,我还想在这里添加请求验证,使用子类Views中定义的Serializer。 我认为适当的地方是把它放在dispatch()
方法中。 但在我调用API.dispatch()
方法之前,没有准备request.data
。 所以,那是行不通的。 有人可以帮我正确指导如何将验证移到一个地方吗?
这是类结构:
class BaseView(APIView):
validation_serializer = None
def dispatch(self, request, *args, **kwargs):
# Some code here
# How to use `validation_serializer` here, to validate request data?
# `request.data` is not available here.
response = super(BaseView, self).dispatch(request, *args, **kwargs)
# Some code here
return response
class MyView(BaseView):
validation_serializer = ViewValidationSerializer
def post(self, request, *args, **kwargs):
pass
我认为另一种方法可能是在post()
方法的顶部使用装饰器。 但是,如果只有一个更清洁的方式,而不是整个项目的装饰器?
注意:它类似于这里的问题: Django - DRF - 调度方法流程 。 但根据那里的建议,我不想只是从DRF源代码复制整个dispatch
方法。
将django请求处理为DRF请求(并添加request.data
属性)的方法是APIView.initialize_request
。 APIView.dispatch()
方法调用它然后继续调用适当的方法处理程序( post / patch / put )。
您可以尝试通过调用它并使用返回的对象来自己完成:
class BaseView(APIView):
validation_serializer = None
def dispatch(self, request, *args, **kwargs):
request = self.initialize_request(request, *args, **kwargs)
kwargs['context'] = self.get_serializer_context()
serializer = self.validation_serializer(data=request.data, *args, **kwargs)
# use `raise_exception=True` to raise a ValidationError
serializer.is_valid(raise_exception=True)
response = super(BaseView, self).dispatch(request, *args, **kwargs)
return response
但是,我建议不要这样做,因为dispatch()
其他功能可能应该在处理验证之前执行; 因此,您可以将上述逻辑移至相关的post / patch / put方法。
在这些方法中,您也可以直接使用self.request
,因为它已经由dispatch()
初始化。
我认为drf-tracking可以满足您的需求。 你可能想看一下。
我不认为你这是正确的方式。 通过验证记录请求的最佳方法是在您的身份验证类中,并将审核日志添加到请求中。
然后,您可以使用您的APIView
记录渲染时间,对照在Authentication Class中生成的AuditLog
。
这是使用令牌认证的示例,假设每个请求都有一个头部Authorization: Bearer <Token>
。
settings.py
...
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'common.authentication.MyTokenAuthenticationClass'
),
...,
}
通用/ authentication.py
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from ipware.ip import get_real_ip
from rest_framework import authentication
from rest_framework import exceptions
from accounts.models import Token, AuditLog
class MyTokenAuthenticationClass(authentication.BaseAuthentication):
def authenticate(self, request):
# Grab the Athorization Header from the HTTP Request
auth = authentication.get_authorization_header(request).split()
if not auth or auth[0].lower() != b'bearer':
return None
# Check that Token header is properly formatted and present, raise errors if not
if len(auth) == 1:
msg = _('Invalid token header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid token header. Credentials string should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
try:
token = Token.objects.get(token=auth[1])
# Using the `ipware.ip` module to get the real IP (if hosted on ElasticBeanstalk or Heroku)
token.last_ip = get_real_ip(request)
token.last_login = timezone.now()
token.save()
# Add the saved token instance to the request context
request.token = token
except Token.DoesNotExist:
raise exceptions.AuthenticationFailed('Invalid token.')
# At this point, insert the Log into your AuditLog table and add to request:
request.audit_log = AuditLog.objects.create(
user_id=token.user,
request_payload=request.body,
# Additional fields
...
)
# Return the Authenticated User associated with the Token
return (token.user, token)
现在,您可以在请求中访问AuditLog。 因此,您可以在验证前后记录所有内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.