Django-rest-framework(二)serializers 使用


簡介

初次見到serializers文件,想必大家都會感到陌生,所以,我們不妨換個詞來形容他的作用,那就是django 中的Form,這樣是不是感覺熟悉了一點。
實際上,serializers 的作用和Form也差不多,可以幫我們驗證提交的表單,和取出model里面的字段

fields

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

# 舉例子
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 只在輸出時顯示,提交數據的時候,跳過

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

source 獲取本字段的方法,會調用model 中對應的方法,我們可以自己定義相關的實現

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

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

ModelSerializer

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

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

    我們先簡單看下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 字段更為方便,清晰。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM