初次見到serializers文件,想必你們都會感到陌生,因此,咱們不妨換個詞來形容他的做用,那就是django 中的Form,這樣是否是感受熟悉了一點。
實際上,serializers 的做用和Form也差很少,能夠幫咱們驗證提交的表單,和取出model裏面的字段python
既然是序列化數據,那麼咱們須要指定對應的一些字段,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
既然在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
字段更爲方便,清晰。