使用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 或有或无罢了。
总结:
- ModelSerializer元类中,如果不指定要序列化的字段,就默认序列化所有字段
- 如果序列化字段中只选择了部分字段,那么序列化输出的也就这几个字段,相对应的反序列化 新增 维护模型实例的时候,只会对序列化类中决定的那几个字段生效,就算 传递进来的data 存在模型中其他字段也一样(比如:上述反序列化例子中的1.传递除了序列化类中指明的字段,还多添加字段 多的字段不会有影响, 并且查询数据库 这里的remarks并没有保存到库中)
- data传递多了字段没事,is_valid()不会False ,只是对多了的字段不做处理。但是少了序列化指明的字段 就会False ,根据ser.errors查看False原因
- id主键这个字段,序列化中如果没有指明该字段,就不会输出出来,但是反序列化中,fields中不管有没有声明id, data中都可以传递或者不传递id,因为 create update时候,对这个id是没有处理的,只会根据数据库中的自增/根据实例instance去更新,所以建议反序列化时候,不需要带上id字段