簡體   English   中英

DRF APIView使用request.data將請求驗證移動到調度方法

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM