Django(44)drf序列化原始碼分析

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

序列化與反序列化

  一般後端資料返回給前端的資料格式都是json格式,簡單易懂,但是我們使用的語言本身並不是json格式,像我們使用的Python如果直接返回給前端,前端用的javascript語言是識別不出的,所以我們需要把python語言轉換為通用的json格式的資料,在django中就是將orm模型或者queryset物件轉換成字典,再由字典轉換成json,整個過程就是序列化。

  當使用者通過在form表單中填寫的資料,傳送請求給後端,將資料提交給後端資料庫,這個過程就是反序列化。反序列化的時候,我們需要去驗證前端提交的資料是否符合後端制定的規範,符合才進行入庫。
 

drf的序列化類

drf的序列化類有3個

  • Serializer
  • ModelSerializer(使用最多的)
  • ListSerializer

我們使用最多的就是ModelSerializer,這三個序列化類都繼承自BaseSerializer,雖然我們專案中99%都是使用的ModelSerializer,但是光知道怎麼使用,是沒有靈魂的,我們還需要去了解原始碼,多看原始碼能迅速提高程式碼能力。
 

BaseSerializer原始碼分析

原始碼如下:

class BaseSerializer(Field):
    def __init__(self, instance=None, data=empty, **kwargs):
     
    def __new__(cls, *args, **kwargs)

    def __class_getitem__(cls, *args, **kwargs)

    @classmethod
    def many_init(cls, *args, **kwargs):

    def to_internal_value(self, data):

    def to_representation(self, instance):

    def update(self, instance, validated_data):

    def create(self, validated_data):

    def save(self, **kwargs):

    def is_valid(self, raise_exception=False):

    @property
    def data(self):

    @property
    def errors(self)

    @property
    def validated_data(self)

我們分析幾個重要的方法,沒必要每個方法都瞭解,分析的都是後面要用到的
 

__init__方法

def __init__(self, instance=None, data=empty, **kwargs):
    self.instance = instance 
    if data is not empty:
        self.initial_data = data
    self.partial = kwargs.pop('partial', False)
    self._context = kwargs.pop('context', {})
    kwargs.pop('many', None)
    super().__init__(**kwargs)

初始化方法,有4個引數

  • self:本身自己
  • instance:例項,預設為None
  • data:資料,預設為empty
  • **kwargs:不定長字典
     

create

def create(self, validated_data):
    raise NotImplementedError('`create()` must be implemented.')

定義了一個create方法,引數為validated_data,方法丟擲了一個異常,意思是create方法沒有定義,如果要繼承BaseSerializer,那就必須定義create方法,否則就會丟擲異常
 

update

def update(self, instance, validated_data):
    raise NotImplementedError('`update()` must be implemented.')

定義了一個update方法,有2個引數

  • instance:例項,更新資料的時候,需要知道更新的是哪個例項化物件
  • validated_data:已驗證的資料,前端傳入的欄位需要進行驗證

此方法丟擲了一個異常,意思是update方法沒有定義,如果要繼承BaseSerializer,那就必須定義update方法,否則就會丟擲異常
 

is_valid

def is_valid(self, raise_exception=False):
    # 如果self物件沒有initial_data屬性,那麼將無法呼叫該方法,如果需要有initial_data,那麼例項化物件必須傳入data引數
    assert hasattr(self, 'initial_data'), (
        'Cannot call `.is_valid()` as no `data=` keyword argument was '
        'passed when instantiating the serializer instance.'
    )

    if not hasattr(self, '_validated_data'):
        try:
            self._validated_data = self.run_validation(self.initial_data)
        except ValidationError as exc:
            self._validated_data = {}
            self._errors = exc.detail
        else:
            self._errors = {}

    if self._errors and raise_exception:
        raise ValidationError(self.errors)

    return not bool(self._errors)

這個方法是驗證從前端傳輸過來的欄位是否驗證成功,如果我們的例項化物件沒有傳入data引數,將會無法呼叫is_valid,這個方法大多數用在反序列化的時候
 

save

def save(self, **kwargs):
    # 呼叫save()方法前必須先呼叫is_valid()
    assert hasattr(self, '_errors'), (
        'You must call `.is_valid()` before calling `.save()`.'
    )
    # 不能對無效的資料呼叫save()方法
    assert not self.errors, (
        'You cannot call `.save()` on a serializer with invalid data.'
    )
    # 防止沒有正確使用save方法
    # Guard against incorrect use of `serializer.save(commit=False)`
    assert 'commit' not in kwargs, (
        "'commit' is not a valid keyword argument to the 'save()' method. "
        "If you need to access data before committing to the database then "
        "inspect 'serializer.validated_data' instead. "
        "You can also pass additional keyword arguments to 'save()' if you "
        "need to set extra attributes on the saved model instance. "
        "For example: 'serializer.save(owner=request.user)'.'"
    )
    # 訪問serializer.data後就不能呼叫save方法了,如果你需要在提交到資料庫之前訪問資料,那麼請使用serializer.validated_data
    assert not hasattr(self, '_data'), (
        "You cannot call `.save()` after accessing `serializer.data`."
        "If you need to access data before committing to the database then "
        "inspect 'serializer.validated_data' instead. "
    )
    # 建立已驗證的資料物件
    validated_data = {**self.validated_data, **kwargs}
    
    # 如果instance不為空
    if self.instance is not None:
        # instance物件將更新為validated_data裡的內容
        self.instance = self.update(self.instance, validated_data)
        assert self.instance is not None, (
            '`update()` did not return an object instance.'
        )
    else:
        # 如果instance為空,那麼則建立物件,物件的內容為validated_data
        self.instance = self.create(validated_data)
        assert self.instance is not None, (
            '`create()` did not return an object instance.'
        )

    return self.instance

相關文章