在返回json数据时,整合DRF后并没有取出QuerySet中的数据,再转字典,也能直接返回json,这就是序列化器的功劳。
- 序列化,序列化器会把模型对象转换成字典,经过response以后变成json字符串
- 反序列化,把客户端发送过来的数据,经过request以后变成字典,序列化器可以把字典转成模型
- 反序列化,完成数据校验功能
1 2 3 4 5 6 7 8
| class StudentModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = '__all__'
|
student序列化器继承了 serializers.ModelSerializer
,这是转为数据库中的表设计的,一一对应,帮我们重写了create()和update()方法,所以与数据库中的表一一对应的字段我们可以直接继承该类,简化代码
对于不是表对应的字段,我们则需要继承 serializers.Serializer
序列化
ModelSerializer
定义的序列化器,继承 serializers.ModelSerializer
,在里面声明Meta类,通过指定对应的模型类和序列化字段即可完成最简单的序列化器编写。
对于单表查询这是非常快的,但是很多情况下我们都是需要在多个表之间进行联合查询。我们对model进行补充,设计外键进行约束,方便联合查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| class Student(models.Model): SEX_OPTION = ( (0,'保密'), (1,'男'), (2,'女'), ) name = models.CharField(max_length=20,verbose_name='姓名',help_text='姓名') age = models.SmallIntegerField(verbose_name='年龄',help_text='年龄') sex = models.SmallIntegerField(choices=SEX_OPTION,verbose_name='性别',help_text='性别,0->保密,1->男,2->女,') classmate = models.CharField(db_column='classmate',max_length=13,verbose_name='班级',help_text='班级') description = models.TextField(null=True,blank=True,verbose_name='个性签名',help_text='个性签名,可以为空')
class Meta: db_table = 'db_student' verbose_name = '学生信息' verbose_name_plural = verbose_name
class Course(models.Model): name = models.CharField(max_length=52,verbose_name='课程名称') teacher = models.ForeignKey('Teacher',on_delete=models.DO_NOTHING,related_name='course',db_constraint=False) class Meat: db_stable = 'db_course' def __str__(self): return self.name
class Teacher(models.Model): name = models.CharField(max_length=50,verbose_name='姓名') sex = models.BooleanField(default=False) class Meta: db_table = 'db_teacher' def __str__(self): return self.name
class Achievement(models.Model): score = models.DecimalField(default=0,max_digits=4,decimal_places=1,verbose_name='成绩') student = models.ForeignKey(Student,on_delete=models.DO_NOTHING,related_name='s_achievement',db_constraint=False) course = models.ForeignKey(Course,on_delete=models.DO_NOTHING,related_name='c_achievement',db_constraint=False) create_time = models.DateTimeField(auto_created=datetime.now) class Meta: db_table = 'db_achievement' def __str__(self): return self.score
|
重新进行模型迁移和数据导入,写入几条测试数据
功能编写:
1 2 3 4 5 6 7 8 9 10 11 12
| class CourseModelSerializer(serializers.ModelSerializer): class Meta: model = Course fields = ['name']
class TeacherCourseModelSerializer(serializers.ModelSerializer): course = CourseModelSerializer(many=True) class Meta: model = Teacher fields = ['id', 'name', 'course']
|
1 2 3 4 5 6 7 8 9
| def get_teacher_course(self,request): ''' 查询老师代课信息 :param request: :return: ''' teacher = Teacher.objects.all() serializer = TeacherCourseModelSerializer(instance=teacher,many=True) return Response(data=serializer.data,status=status.HTTP_200_OK)
|
这是第一种,需要外面写个序列化器,代码显得很冗余,第二种直接写里面,第三种是指明嵌套深度
1 2 3 4 5 6 7 8 9 10
| class TeacherCourseModelSerializer(serializers.ModelSerializer): class Meta: model = Teacher fields = ['id', 'name', 'course'] depth = 1
|
第四种是通过外键指明深度,直接访问
1 2 3 4 5 6 7
| class StudenAchievementModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = ['id','name','s_achievement'] depth = 1
|
这四种实现的效果类似,都有层层嵌套,不好识别的问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Student(models.Model): SEX_OPTION = ( (0,'保密'), (1,'男'), (2,'女'), ) name = models.CharField(max_length=20,verbose_name='姓名',help_text='姓名') age = models.SmallIntegerField(verbose_name='年龄',help_text='年龄') sex = models.SmallIntegerField(choices=SEX_OPTION,verbose_name='性别',help_text='性别,0->保密,1->男,2->女,') classmate = models.CharField(db_column='classmate',max_length=13,verbose_name='班级',help_text='班级') description = models.TextField(null=True,blank=True,verbose_name='个性签名',help_text='个性签名,可以为空')
class Meta: db_table = 'db_student' verbose_name = '学生信息' verbose_name_plural = verbose_name
def __str__(self): return self.name @property def achievement(self): queryset = self.s_achievement.all() ret = [{'score': item.score, 'course': item.course.name, 'teacher': item.course.teacher.name} for item in queryset] return ret
|
1 2 3 4 5
| class StudentAchievement2ModelSerializer(serializers.ModelSerializer): class Meta: model = Student fields = ['id','name','achievement']
|
反序列化
Serializer
Serializer的数据并不是来自数据库,所以我们在使用该类时需要自己去声明
1 2 3 4 5 6 7 8 9 10 11
|
class StudentSerializer(serializers.Serializer): id = serializers.IntegerField(read_only=True) name = serializers.CharField(max_length=20,required=True) classmate = serializers.CharField(max_length=4,required=True) age = serializers.IntegerField() sex = serializers.IntegerField(validators= [check_sex,]) description = serializers.CharField(required=False,default='这家伙很懒,什么也没写!')
|
和ModelSerializer类似,因为ModelSerializer的数据来自数据库,所以直接与model关联即可,但Serializer的数据并不是来自数据库,需要手动声明。
在进行添加和更新数据操作时,ModelSerializer已经帮我们实现了create()和update()方法,但Serializer并没有实现,需要我们手动实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| def create(self, validated_data): student = Student.objects.create(**validated_data) return student
def update(self, instance, validated_data): ''' :param instance: 更新的模型对象数据 :param validated_data: 新数据 :return: ''' if validated_data.get('name'): instance.name = validated_data.get('name') if validated_data.get('age'): instance.age = validated_data.get('age') if validated_data.get('sex'): instance.sex = validated_data.get('sex') if validated_data.get('classmate'): instance.classmate = validated_data.get('classmate') if validated_data.get('description'): instance.description = validated_data.get('description') instance.save() return instance
|
数据校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| def validate_name(self,data): print(f'验证参数:{data}') if data == 'Python': raise serializers.ValidationError(code='name',detail='当前输入存在敏感数据') return data
def validate(self, attrs): age = attrs.get('age') classmate = attrs.get('classmate') if (age < 20) and str(classmate).startswith('5'): raise serializers.ValidationError('对不起!年龄20以下不能加入到5字开头的班级中') return attrs
|
做校验的数据是从客户端发来的,有的并不和数据库中字段一一对应,所以就不能用model声明的约束去控制了,需要手动判断。
序列化器的使用
当编写完序列化器后,可以在视图层是直接视图
更新和删除
1 2 3 4
| student = Student.objects.get(pk=pk) serializer = StudentModelSerializer(instance=student,data=params) serializer.is_valid(raise_exception=True) serializer.save()
|
这段是更新student的代码,通过接受的id去查询原信息,然后把原信息和客户端提交的信息放入序列化器,instance
传入数据库查到的数据,data
传入客户端提交的信息,is_valid
进行参数校验,raise_exception=True
是设置抛出异常,最后调用序列化器的save
保存数据。
对于删除操作,很多时候并不是在数据库中把数据给删除掉,相反是修改IsDeleted
的值,与更新操作类似
查询list和根据ID查询
1 2
| teacher = Teacher.objects.all() serializer = TeacherCourseModelSerializer(instance=teacher,many=True)
|
需要在放入序列化器的时候传入 many=True
,内部会调用循环返回所有查询到的数据
根据ID查询某单个数据,不传 many
即可,默认是 False
添加操作
1 2 3 4
| param = request.data.dict() serializer = TeacherModelSerializer(data=param) serializer.is_valid(raise_exception=True) serializer.save()
|