[英]DRF APIView move request validation to dispatch method using request.data
I've created a base api view, which extends from APIView
, where I log response time, log request, and other common stuffs. 我已经创建了一个基本api视图,它从
APIView
扩展,在那里我记录响应时间,日志请求和其他常见的东西。
Now, I also want to add request validation here, using the Serializer defined in sub-class Views. 现在,我还想在这里添加请求验证,使用子类Views中定义的Serializer。 I thought the appropriate place is to put that in
dispatch()
method. 我认为适当的地方是把它放在
dispatch()
方法中。 But before I call API.dispatch()
method, request.data
is not prepared. 但在我调用
API.dispatch()
方法之前,没有准备request.data
。 So, that won't work. 所以,那是行不通的。 Can someone help me in right direction as to how to move validation to a single place?
有人可以帮我正确指导如何将验证移到一个地方吗?
Here's the class structure: 这是类结构:
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
I thought another approach could be use decorator on the top of post()
method. 我认为另一种方法可能是在
post()
方法的顶部使用装饰器。 But if only there was an cleaner way, than putting decorators all across the project? 但是,如果只有一个更清洁的方式,而不是整个项目的装饰器?
Note: It's similar to the question here: Django - DRF - dispatch method flow . 注意:它类似于这里的问题: Django - DRF - 调度方法流程 。 But as per the suggestion there, I don't want to just copy the entire
dispatch
method from DRF source code. 但根据那里的建议,我不想只是从DRF源代码复制整个
dispatch
方法。
The method that processes the django request into a DRF request (and adds the request.data
property) is the APIView.initialize_request
. 将django请求处理为DRF请求(并添加
request.data
属性)的方法是APIView.initialize_request
。 The APIView.dispatch()
method calls it and then proceeds to call the appropriate method handler ( post/patch/put ). APIView.dispatch()
方法调用它然后继续调用适当的方法处理程序( post / patch / put )。
You can try to do that yourself by calling it and using the returned object: 您可以尝试通过调用它并使用返回的对象来自己完成:
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
However, I would suggest against this, as other functionality of dispatch()
probably should be performed prior to handling validation; 但是,我建议不要这样做,因为
dispatch()
其他功能可能应该在处理验证之前执行; thus, you could moving the above logic to the relevant post/patch/put methods instead. 因此,您可以将上述逻辑移至相关的post / patch / put方法。
In these methods you can also use self.request
directly since it was already initialized by dispatch()
. 在这些方法中,您也可以直接使用
self.request
,因为它已经由dispatch()
初始化。
I think drf-tracking does what you are looking for. 我认为drf-tracking可以满足您的需求。 You may want to check it out.
你可能想看一下。
I don't think you're going about this the correct way. 我不认为你这是正确的方式。 The best way to log the request, with validation is in your Authentication Class and add the audit log to the request.
通过验证记录请求的最佳方法是在您的身份验证类中,并将审核日志添加到请求中。
Then you can use your APIView
to log the render time, against the AuditLog
generated in the Authentication Class. 然后,您可以使用您的
APIView
记录渲染时间,对照在Authentication Class中生成的AuditLog
。
Here's an example using Token Authentication, assuming each request has a header Authorization: Bearer <Token>
. 这是使用令牌认证的示例,假设每个请求都有一个头部
Authorization: Bearer <Token>
。
settings.py settings.py
...
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'common.authentication.MyTokenAuthenticationClass'
),
...,
}
common/authentication.py 通用/ 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)
Now, you have access to the AuditLog in your request. 现在,您可以在请求中访问AuditLog。 So you can log everything before and after validation.
因此,您可以在验证前后记录所有内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.