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字段
原文地址:https://www.cnblogs.com/alantammm/p/14518663.html