• DRF__序列化(2)serializers.ModelSerializer


    使用ModelSerializer的优缺点:

    • 更少的代码
    • 根据model模型的定义,自动生成默认字段
    • 自动生成序列化器的验证器,比如unique_together验证器
    • 自动实现了简单的.create()方法和.update()方法
    • 可定制性会比serializers.Serializer低

    还是接上篇文章的例子,存在如下的模型类:

    from django.db import models
    
    # Create your models here.
    class Person(models.Model):
      name = models.CharField(max_length=50)
      gender = (('男','M'),('女','f'))
      sex = models.CharField(choices=gender,max_length=50)
      remarks = models.TextField()
      class Meta:
        db_table = 'person'
      def __str__(self):
        return self.name
    

    修改serializers.py中的PersonSerializers类如下:

    class PersonSerializers(serialzers.ModelSerializer):
      class Meta:
        #要序列化的模型
        model = Person
        #要序列化的字段,默认是全部字段  "__all__",也可以用 元祖 或者 列表  序列化指定的字段
        #fields = []
    
    

    测试一下序列化:

    >>> from drf.models import *
    >>> from drf.models import *
    >>> from drf.serializers import *
    >>> instance = Person.objects.get(id=1)
    >>> instance
    <Person: kobe>
    >>> ser = PersonSerializers(instance)
    >>> ser.data
    {'id': 1, 'name': 'kobe', 'sex': 'M', 'remarks': '科比布莱恩特'}
    
    
    
    >>> queryset = Person.objects.all()
    >>> ser = PersonSerializers(instance = queryset,many=True)
    >>> ser.data
    [OrderedDict([('id', 1), ('name', 'kobe'), ('sex', 'M'), ('remarks', '科比布莱恩特')]), OrderedDict([('id', 2), ('name', 'james'), ('sex', 'M'), ('remarks', '
    勒布朗詹姆斯')]), OrderedDict([('id', 3), ('name', 'paulxxx'), ('sex', 'M'), ('remarks', '999')])]
    

    测试一下反序列化:

    >>> data = { 'name': 'xx', 'sex': '男', 'remarks': 'xxx'}   ###这里sex不能写M 只能用前面的 男 不然 ser.is_valid = False  ser.errors 为:{'sex': [ErrorDetail(string='"M" #is not a valid choice.', code='invalid_choice')]}
    >>> ser = PersonSerializers(data=data)
    >>> ser.is_valid()
    True
    >>> ser.save()
    <Person: xx>
    
    
    >>> data = { 'id':1,'name': 'aa', 'sex': '男', 'remarks': 'aaa'}
    >> instance = Person.objects.get(id=2)
    >>> instance
    <Person: james>
    >>> ser = PersonSerializers(instance=instance,data=data)
    >>> ser.is_valid()
    True
    >>> ser.save()
    <Person: aa>
    

    这里发现,序列化的时候,主键id自增,比如现在表中只有三个数据,这时候就 data = { 'id':8,'name': 'aa', 'sex': '男', 'remarks': 'aaa'} ,序列化然后save调用create方法,增加的这个data对应的模型实例id=4,只会自增,不是说传的什么进去就是什么。 当然data={ 'name': 'xx', 'sex': '男', 'remarks': 'xxx'} 不传递id 进去也是一样的,也是一样可以正常序列化 create update
    上面这个update的demo也说明了,我传递进去的data是id=1,但是我实例instance是id=2的,这里最后修改的还是id=2的数据 james 改成了 aa
    在反序列化中,只读字段不会参与,在后续测试外键关联的反序列化时候,会体验的更加清晰

    只序列化部分字段的时候

    修改PersonSerializers类如下:

    class PersonSerializers(serializers.ModelSerializer):
        class Meta:
            #声明需要序列化的模型类
            model = Person
            #默认序列化的是所有字段 "__all__" 或者是一个元祖  或者是一个列表
            fields = ('name','sex',)
    

    以上序列化类只序列化了 name sex 两个字段

    测试一下序列化:

    >>> ser = PersonSerializers(Person.objects.get(id=1))
    >>> ser.data
    {'name': 'kobe', 'sex': 'M'}
    

    测试一些反序列化 create update

    #### 1.传递除了序列化类中指明的字段,还多添加字段    多的字段不会有影响, 并且查询数据库 这里的remarks并没有保存到库中
    >>> data = { 'id':8,'name': 'bb', 'sex': '男', 'remarks': 'aaa'}
    >>> ser = PersonSerializers(data=data)
    >>> ser.is_valid()
    True
    >>> ser.save()
    <Person: bb>  #这里只会保存 name  sex两个字段,就算data中有remarks,但是是没被反序列化保存入库的
    
    #### 2.少传了序列化类中指明的字段     is_valid() 会False
    >>> data = { 'id':8,'name': 'bb',  'remarks': 'aaa'}
    >>> ser=PersonSerializers(data=data)
    >>> ser.is_valid()
    False
    >>> ser.errors
    {'sex': [ErrorDetail(string='This field is required.', code='required')]}
    

    测试只update部分字段

    当反序列化更新实例信息的时候,有时候只需要更新部分字段,比如更新姓名,这时候就需要加到参数 partial=True

    举例说明:

    >>> person = Person.objects.get(id=1)
    >>> data={'name':'kobebryant'}
    >>> ser = PersonSerializers(instance=person,data=data,partial=True)###partial=True
    >>> ser.is_valid()
    True
    >>> ser.save()
    <Person: kobebryant> ###姓名修改为了Kobebryant
    
    #传递部分序列化类中没有的字段的时候
    >>> data = {'name':'kkkkkkkkobe','cff':'dsds'}
    >>> ser = PersonSerializers(instance=person,data=data,partial=True)
    >>> ser.is_valid()
    True
    >>> ser.save()
    <Person: kkkkkkkkobe>
    
    #传递的字段全部不在序列化类中
    >>> data ={'dsd':'dsa','dsa':'dd'}
    >>> ser = PersonSerializers(instance=person,data=data,partial=True)
    >>> ser.is_valid()
    True
    >>> ser.validated_data
    OrderedDict()
    >>> data={}
    >>> ser = PersonSerializers(instance=person,data=data,partial=True)
    >>> ser.is_valid()
    True
    >>> ser.validated_data
    OrderedDict()
    

    可见当传递进入partial=True进去之后,所有的字典类型数据传递进去 is_valid()都会是True, 只是validated_data 或有或无罢了。

    总结:

    1. ModelSerializer元类中,如果不指定要序列化的字段,就默认序列化所有字段
    2. 如果序列化字段中只选择了部分字段,那么序列化输出的也就这几个字段,相对应的反序列化 新增 维护模型实例的时候,只会对序列化类中决定的那几个字段生效,就算 传递进来的data 存在模型中其他字段也一样(比如:上述反序列化例子中的1.传递除了序列化类中指明的字段,还多添加字段 多的字段不会有影响, 并且查询数据库 这里的remarks并没有保存到库中)
    3. data传递多了字段没事,is_valid()不会False ,只是对多了的字段不做处理。但是少了序列化指明的字段 就会False ,根据ser.errors查看False原因
    4. id主键这个字段,序列化中如果没有指明该字段,就不会输出出来,但是反序列化中,fields中不管有没有声明id, data中都可以传递或者不传递id,因为 create update时候,对这个id是没有处理的,只会根据数据库中的自增/根据实例instance去更新,所以建议反序列化时候,不需要带上id字段
  • 相关阅读:
    findIndex() 方法用法
    Centos7安装nginx1.17.5,集成upstream和stream
    Centos7安装docker
    LeetCode(C++)刷题计划:17-电话号码的字母组合
    LeetCode(C++)刷题计划:16-最接近的三数之和
    LeetCode(C++)刷题计划:15-三数之和
    LeetCode(C++)刷题计划:14-最长公共前缀
    LeetCode(C++)刷题计划:13-罗马数字转整数
    LeetCode(C++)刷题计划:12-整数转罗马数字
    LeetCode(C++)刷题计划:11-盛最多水的容器
  • 原文地址:https://www.cnblogs.com/alantammm/p/14518663.html
Copyright © 2020-2023  润新知