drf基本使用(2)_Serializer的使用
反序列化
数据校验
使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。
在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False。
验证失败,可以通过序列化器对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。如果是非字段错误,可以通过修改REST framework配置中的NON_FIELD_ERRORS_KEY来控制错误字典中的键名。
验证成功,可以通过序列化器对象的validated_data属性获取数据。获取的是一个有序的字典类型的数据
在定义序列化器时,指明每个字段的序列化类型和选项参数,本身就是一种验证行为。
为了方便演示效果,我们单独创建一个子应用student。
python manage.py startapp student
创建我们的模型类
from django.db import models
# Create your models here.
class Student(models.Model):
# 模型字段
name = models.CharField(max_length=100,verbose_name="姓名",help_text='提示文本:不能为空')
sex = models.BooleanField(default=1,verbose_name="性别")
age = models.IntegerField(verbose_name="年龄")
class_null = models.CharField(max_length=5,verbose_name="班级编号")
description = models.TextField(max_length=1000,verbose_name="个性签名")
class Meta:
db_table="tb_student"
verbose_name = "学生"
verbose_name_plural = verbose_name
validators自定义校验函数
在student应用下创建一个序列化器
虽然我们序列化器的字段中提供了一些校验方法,但还是不能满足我们的需求,这个时候你可以在字段中添加validators参数补充验证行为
这里我们定义了一个check_name函数对输入的名字进行校验
from rest_framework import serializers
# 自定义校验函数
def check_name(val):
import re
if not re.match('a', val): # 如果不是以a开头的直接抛出异常,被serializer.error捕获到
raise serializers.ValidationError('名字不是以a开头的')
return val
class StudentSerializer(serializers.Serializer):
# 需要进行数据转转的字段
id = serializers.IntegerField(read_only=True)
# 使用validators进行校验
name = serializers.CharField(validators=[check_name,])
sex = serializers.BooleanField(default=1)
age = serializers.IntegerField(max_value=30)
class_null = serializers.CharField(required=False) # 这个字段不填的话orm会自动向我们的数据库中添加一个空字符串
views视图
from django.http import JsonResponse
from rest_framework.views import APIView
from student.serializer import StudentSerializer
from student import models
class StudentAPIView(APIView):
def get(self, request):
student = models.Student.objects.all()
# 进行序列化
serializer = StudentSerializer(instance=student, many=True) # 对多条数据进行序列化时指定many=True
# 序列化多条数据得到的是列表套字典,所以要指定safe=False
return JsonResponse(serializer.data,safe=False,json_dumps_params={'ensure_ascii': False})
def post(self, request):
print(request.data) #{'name': 'bb哥', 'age': 12, 'sex': 0}
serializer = StudentSerializer(data=request.data)
serializer.is_valid(raise_exception=True) # 如果返回False,直接抛出异常,,前端返回400错误
if serializer.is_valid():
# 成功后获取数据
print(serializer.validated_data)
return JsonResponse({'message':'ok'})
print('错误信息', serializer.errors)
return JsonResponse({'error':'校验失败'})
is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。
局部钩子校验validate_字段名
局部钩子就是在序列化器中定义的一个函数,函数名为vallidatae_字段名
反序列化的时的执行顺序:
字段1的参数效验=> 字段1的局部构子校验=>字段2的参数校验,=>字段2的局部钩子校验
class StudentSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(validators=[check_name,])
sex = serializers.BooleanField(default=1)
age = serializers.IntegerField(max_value=30)
class_null = serializers.CharField(required=False)
# 局部钩子校验 执行顺序在字段中的校验之后,也是自动触发的
def validate_age(self, data):
if data > 20:
raise serializers.ValidationError('老女人')
return data
- views中打印的错误信息
print('错误信息', serializer.errors)
# 错误信息 {'age': [ErrorDetail(string='老女人', code='invalid')]}
全局钩子校验 validate
在序列化器中需要同时对多个字段就行比较时,可以定义validate方法来验证
validate在所有的校验之后自动触发执行
class StudentSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(validators=[check_name,])
sex = serializers.BooleanField(default=1)
age = serializers.IntegerField(max_value=30)
class_null = serializers.CharField(required=False) #
# 比如我们要对两次密码进行教验
p1 = serializers.CharField()
p2 = serializers.CharField()
def validate_age(self, data):
if data > 20:
raise serializers.ValidationError('老女人')
return data
# 全局钩子校验
def validate(self, data): # data是所有的校验完成之后返回的一个有序字典
print('>>',data)
# >> OrderedDict([('name', 'aa哥'), ('sex', False), ('age', 18), ('p1', 123), ('p2', 222)])
p1 = data.get('p1')
p2 = data.get('p2')
if p1 != p2:
raise serializers.ValidationError('两次密码不一致')
return data
删除传过来的不需要的字段
上面我们对两次密码进行了校验,但是我们对数据进行保存的时候,只需要一个就够了
# 删除方式一: 使用pop删除
我们需要对字段进行修改才能使用pop方法
password = serializers.CharField(max_length=5, wirte_only=True) # 加上wirte_only的字段可以直接删除
# 在视图中
serializer.validated_data.pop('password')
# 删除方式二: 重写create方法
后端通过save()方法保存数据的时候,会触发ModelSerializer中的create方法
def create(self, validated_data): # validated_data 是反序列化之后的数据
validated_data.pop('password')
instance = super().create(validated_data)
return instance
serializer对象中的context参数
比如我们想要在全局钩子中获取一下当前的请求路径,怎么搞呢
我们可以通过context传递这个参数, 当我们序列化器执行is_valid()的时候 就会执行序列化器中的全局钩子 , 我们可以通过self.context获取
serializer = AccountSerializer(account, context={'request': request})
- views
def post(self, request):
print(request.data)
serializer = StudentSerializer(data=request.data,context={'request': request}) # 传递request对象
if serializer.is_valid():
return JsonResponse({'message':'ok'})
print('错误信息', serializer.errors)
return JsonResponse({'error':'校验失败'})
- serializer
这里获取到的request是经过rest_framework的APIView重新封装后的request对象了
class StudentSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(validators=[check_name,])
sex = serializers.BooleanField(default=1)
age = serializers.IntegerField(max_value=30)
class_null = serializers.CharField(required=False)
p1 = serializers.IntegerField()
p2 = serializers.IntegerField()
# 全局钩子校验
def validate(self, data):
print('context',self.context) # context {'request': <rest_framework.request.Request: POST '/stu/students/'>}
request = self.context.get('request')
print(request.path) # /stu/students/
p1 = data.get('p1')
p2 = data.get('p2')
if p1 != p2:
raise serializers.ValidationError('两次密码不一致')
return data
反序列化后保存数据
这里我们重新创建一个应用进行添加数据
方式一 : 直接保存,通过create
- 创建序列化器
from rest_framework import serializers
class AvSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(allow_blank=False, allow_null=False)
age = serializers.IntegerField()
sex = serializers.BooleanField()
class_null = serializers.CharField()
description = serializers.CharField()
- views
from student import models
from ser.serializer import AvSerializer
from django.http import JsonResponse
class AvAPIView(APIView):
def get(self, request):
student = models.Student.objects.get(id=1)
serializer = AvSerializer(instance=student)
return JsonResponse(serializer.data, safe=False, json_dumps_params={'ensure_ascii': False})
def post(self, request):
print(request.data) # Apiview帮我们处理数据到data中
serializer = AvSerializer(data=request.data)
if serializer.is_valid():
data = serializer.validated_data # 序列化后的数据
# 方式一 直接保存
models.Student.objects.create(**data)
return JsonResponse({'message': '添加成功'})
print(serializer.errors)
return JsonResponse({'error': '校验失败'})

方式二
通过serializer对象的save()方法来触发序列化器中的create来保存
- views
from rest_framework.views import APIView
from student import models
from ser.serializer import AvSerializer
from django.http import JsonResponse
class AvAPIView(APIView):
def get(self, request):
student = models.Student.objects.get(id=1)
serializer = AvSerializer(instance=student)
return JsonResponse(serializer.data, safe=False, json_dumps_params={'ensure_ascii': False})
def post(self, request):
serializer = AvSerializer(data=request.data)
if serializer.is_valid():
data = serializer.save() # 在执行AcSerializer中的create,data是接受返回的数据
# 序列化后在返回i给前端
res = AvSerializer(instance=data)
return JsonResponse(res.data, safe=False)
return JsonResponse({'error': '校验错误'})
- serializer.py
from rest_framework import serializers
from student import models
class AvSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(allow_blank=False, allow_null=False)
age = serializers.IntegerField()
sex = serializers.BooleanField()
class_null = serializers.CharField()
description = serializers.CharField()
# save自动触发
def create(self, validated_data):
print(validated_data) # 校验成功后的数据
data = models.Student.objects.create(**validated_data)
return data # 记得添加后一定要返回

可以看到我们添加成功了,前端也返回了我们添加的数据

更新数据
这里我们用postman提交put请求更新数据, 携带着id提交,
然后后端根据id获取到模型对象进行更新一下用户的名字
方式一: 直接更新

- views
class AvAPIView(APIView):
def put(self, request):
id = request.data.get('id') # 不要忘记了这里使用request.data是因为我们使用了APIView
student_query = models.Student.objects.filter(pk=id)
serializer = AvSerializer(data=request.data, partial=True)
# partial=True进行部分字段校验,传递过来哪个字段就校验哪个字段,没有传递的不校验
if serializer.is_valid():
student_query.update(**serializer.validated_data) # update返回的是更新的条数
student_obj = student_query.first() # student_obj 是更新后的记录对象
serializer_new = AvSerializer(instance=student_obj) # 将更新后的在序列号后返回
return JsonResponse(serializer_new.data)
return JsonResponse({'error':'更新失败'})
方式二 save方法
- serializer
class AvSerializer(serializers.Serializer):
# instance 是老的模型类对象
def update(self, instance, validated_data):
instance.name = validated_data.get('name')
instance.age = validated_data.get('age')
instance.save() # orm的save方法
print(instance)
return instance
- views
class AvAPIView(APIView):
def put(self, request):
id = request.data.get('id')
student_query = models.Student.objects.filter(pk=id)
student_obj = student_query.first()
# 创建序列化器对象
serializer = AvSerializer(data=request.data,partial=True, instance=student_obj)
# 实例化序列化器对象时,如果传递的instance是模型类对象,那么通过serializer.save会触发执行类中的update方法
if serializer.is_valid():
data = serializer.save()
serializer_new = AvSerializer(instance=data)
return JsonResponse(serializer_new.data)
return JsonResponse({'error': '更新失败'})
本文来自博客园,作者:长情不羁的五年,转载请注明原文链接:https://www.cnblogs.com/grlend/articles/14143396.html

浙公网安备 33010602011771号