Django(49)drf解析模組原始碼分析

Silent丿丶黑羽發表於2021-06-08

前言

上一篇分析了請求模組的原始碼,如下:

def initialize_request(self, request, *args, **kwargs):
    """
    Returns the initial request object.
    """
    parser_context = self.get_parser_context(request)

    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )

上述原始碼中parsers=self.get_parsers()就是解析模組原始碼的入口
 

原始碼分析

我們點選get_parsers進入檢視該方法

def get_parsers(self):
    """
    Instantiates and returns the list of parsers that this view can use.
    """
    return [parser() for parser in self.parser_classes]

該方法例項化並返回此檢視可以使用的解析器列表,我們點選parser_classes,檢視解析器列表

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)

parser_classes = api_settings.DEFAULT_PARSER_CLASSES

我們會發現解析器列表,是從api_settings中的DEFAULT_PARSER_CLASSES查詢的,而api_settings又等於APISettings中的DEFAULTS,我們可以從settings中的DEFAUITS列表的DEFAULT_PARSER_CLASSES,如下:

DEFAULTS = {
    # Base API policies
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ],
}

我們可以看到,drf預設的解析器列表中有3個解析器,這3個解析器中都有media_type屬性,代表支援解析的資料提交型別

  • JSONParser:media_type = 'application/json'
  • FormParser:media_type = 'application/x-www-form-urlencoded'
  • MultiPartParser: media_type = 'multipart/form-data'

如果我們想在以上3個解析器的基礎上,再加上檔案型別的解析器,那麼需要全域性配置。
 

全域性配置

我們可以在settings.py檔案中設定REST_FRAMEWORK配置,具體設定如下:

REST_FRAMEWORK = {
    'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser',
            'rest_framework.parsers.FileUploadParser'
        ],
}

這樣,我們以後所有繼承於APIView的類檢視都可以解析上面配置的4種資料型別,但是如果我們想某個檢視只能解析json格式的資料,那麼就需要區域性配置
 

區域性配置

預設全域性配置是因為我們寫的檢視繼承自APIViewAPIView中配置了類屬性parser_classes,所以我們自己編寫的檢視函式中,也設定個類屬性,並且匯入JSONParser解析器

from rest_framework.parsers import JSONParser
class TestView(APIView):
    # 區域性解析類配置
    parser_classes = [JSONParser]

    def post(self, request, *args, **kwargs):
        print(request.data)
        return Response("drf post ok")

接著我們使用application/x-www-form-urlencoded提交資料,會有如下報錯

{
    "detail": "不支援請求中的媒體型別 “application/x-www-form-urlencoded”。"
}

然後我們使用multipart/form-data提交資料,也會報錯

{
    "detail": "不支援請求中的媒體型別 “multipart/form-data; boundary=--------------------------022567055086460827891894”。"
}

最後我們使用application/json提交資料,響應成功

"drf post ok"

 

自定義解析器

如果我們想自定義一個解析器,也很簡單,預設的3個解析器都繼承自BaseParser,我們檢視下原始碼

class BaseParser:
    """
    All parsers should extend `BaseParser`, specifying a `media_type`
    attribute, and overriding the `.parse()` method.
    """
    media_type = None

    def parse(self, stream, media_type=None, parser_context=None):
        """
        Given a stream to read from, return the parsed representation.
        Should return parsed data, or a `DataAndFiles` object consisting of the
        parsed data and files.
        """
        raise NotImplementedError(".parse() must be overridden.")

如果我們需要自定義解析器,那麼就必須繼承自BaseParser,並且設定屬性media_type,還要重寫parse方法,有需求的小夥伴可以自行嘗試,這裡就不演示了

相關文章