Django-rest-framework(二)serializers 使用

簡介

初次見到serializers文件,想必你們都會感到陌生,因此,咱們不妨換個詞來形容他的做用,那就是django 中的Form,這樣是否是感受熟悉了一點。
實際上,serializers 的做用和Form也差很少,能夠幫咱們驗證提交的表單,和取出model裏面的字段python

fields

既然是序列化數據,那麼咱們須要指定對應的一些字段,serializers中的字段和model中的相似,有BooleanField,CharField,IntegerField等,不一樣地方在於model中有ForeignKey,在serializers中沒有,對於這一部分,咱們可使用SerializerMethodField來處理(文章後面會介紹)。
例如django

# 舉例子
mobile = serializers.CharField(max_length=11, min_length=11)
age = serializers.IntegerField(min_value=1, max_value=100)
# format能夠設置時間的格式,下面例子會輸出如:2018-1-24 12:10
pay_time = serializers.DateTimeField(read_only=True,format='%Y-%m-%d %H:%M')
recv_people = serializers.DictField(read_only=True, source='recv_people_info')
settlementinvoicemodel = SettlementInvoiceSerializers(read_only=True, many=False,  required=False)
nego = serializers.DictField(read_only=True, source='nego_info')
  • 經常使用通用參數

read_only 只在輸出時顯示,提交數據的時候,跳過api

write_only 同read_only 相反,只在提交數據時用post

source 獲取本字段的方法,會調用model 中對應的方法,咱們能夠本身定義相關的實現fetch

label 字段的顯示,方便api頁面文檔的顯示ui

help_text 提示文字,方便api頁面文檔的顯示3d

ModelSerializer

既然在model中,咱們有定義了字段的類型信息等,而這一部分和serializer中的相似,因此咱們就想能不能簡化這部分操做,不用按照model中的字段一個一個添加。正好ModelSerializer幫咱們解決了這種問題,咱們只須要對model中的字段作選擇要哪些,或者不要哪些就好了。code

# 獲取Permission model 中除status之外的字段, 而且user 爲只讀
class PermissionSerializers(serializers.ModelSerializer):
    class Meta:
        model = Permission
        read_only_fields = ("user",) # 定義read_only_fields
        exclude = ("status",)
  • 處理save的流程
    流程以下圖所示
    orm

    咱們先簡單看下viewset中的create mixin和update mixin源碼,以下對象

    class CreateModelMixin(object):
        """
        Create a model instance.
        """
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data)
            serializer.is_valid(raise_exception=True) # 必須先調用is_valid 驗證才能調用save
            self.perform_create(serializer)
            headers = self.get_success_headers(serializer.data)
            return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
    
        def perform_create(self, serializer):
            serializer.save()
    
    class UpdateModelMixin(object):
        """
        Update a model instance.
        """
        def update(self, request, *args, **kwargs):
            partial = kwargs.pop('partial', False)
            instance = self.get_object()
            serializer = self.get_serializer(instance, data=request.data, partial=partial)
            serializer.is_valid(raise_exception=True)
            self.perform_update(serializer)
    
            if getattr(instance, '_prefetched_objects_cache', None):
                instance._prefetched_objects_cache = {}
    
            return Response(serializer.data)
    
        def perform_update(self, serializer):
            serializer.save()

    其中用到了get_serializer方法,和serializer相關,因此也貼出這部分的源碼

    def get_serializer(self, *args, **kwargs):
        """
        Return the serializer instance that should be used for validating and
        deserializing input, and for serializing output.
        """
        serializer_class = self.get_serializer_class()
        kwargs['context'] = self.get_serializer_context()
        return serializer_class(*args, **kwargs)

    在create,update中都用到了serializer.save()方法,咱們在來看看save中作了什麼操做

    def save(self, **kwargs):
        # 去掉了assert 出來的錯誤信息
        assert not hasattr(self, 'save_object')
        assert hasattr(self, '_errors')
        assert not self.errors 
        assert 'commit' not in kwargs
        assert not hasattr(self, '_data')
    
        validated_data = dict(
            list(self.validated_data.items()) + 
            list(kwargs.items())
        )
    
        # 根據傳入的instance 對象 判斷是create 仍是update
        if self.instance is not None:
            self.instance = self.update(self.instance, validated_data)
            assert self.instance is not None
        else:
            self.instance = self.create(validated_data)
            assert self.instance is not None
        return self.instance

    能夠看出,最終的create,update方法到了咱們本身定義的serialiers的create, update 方法,在有額外的需求的時候,咱們常常在這裏修改。

  • validate
    ModelSerializer 已經自帶了根據model中的字段來驗證數據,可不少時候,咱們須要額外的認爲加一些判斷,此時,我麼能夠本身寫serializers.validate方法,以下,

    def validate(self, data):
         cellphone = data.get('cellphone', '')
         phone_rst = PHONE_REG.search(str(cellphone)) # 對電話啊號碼作正則驗證
         if phone_rst is not None:
             phone = phone_rst.group(0)
         else:
             phone = ''
         assert cellphone == phone, '手機號格式錯誤'
         data['cellphone'] = cellphone
         return data
  • 序列化數據
    前面講了post,update model, 接下來,咱們來看看怎麼使用serializer序列話咱們的輸出。通常的,咱們是基於model中的字段進行開發,這部分數據不須要單獨處理。可問題是,在開發過程當中,常常會增長一些其餘的字段來返回,因此咱們來看看serializer中增長其餘字段數據的方法。
    第一種方式 是使用 source 參數, 前面介紹字段的時候說過了。還有一種就是使用SerializerMethodField 字段,使用方法以下

    items = serializers.SerializerMethodField()
    # 定義items的獲取
    def get_items(self, obj):
        qs = obj.profile_set.filter(status=True)
        serializer = ProFileSerializers(qs, many=True) # 從另外一個serializer獲取數據
        ret = serializer.data
        return ret
  • 外鍵的序列化
    能夠將寫好的serializers 直接挪過來,像下面這樣

    class SeSerializers(serializers.ModelSerializer):
        cat = CatSerializers(read_only=True, many=True)

    實際的使用中,我的感受仍是使用SerializerMethodField 字段更爲方便,清晰。

相關文章
相關標籤/搜索