zoukankan      html  css  js  c++  java
  • 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 字段更为方便,清晰。

  • 相关阅读:
    CodeForces Round #678(Div2) E.Complicated Computations Mex性质,权值线段树
    P6075 子集选取 思维
    HDU-4747 Mex 线段树应用 Mex性质
    P1273 有线电视网 树形DP 树上背包
    P6786 GCDs & LCMs 数学推导
    [CTSC1997] 选课 树上背包
    Gym-101915K Poor Ramzi 区间DP
    [MdOI R2] Odyssey 拓扑排序上DP
    CodeForces Div3.F
    二分-B
  • 原文地址:https://www.cnblogs.com/yuzhenjie/p/10346120.html
Copyright © 2011-2022 走看看