1.to_internal_value方法
def to_internal_value(self, data):
1.1 to_internal_value方法,是所有字段开始校验时的入口方法,最先调用
1.2 会依次对序列化器类的各个字段进行校验,校验顺序:
对字段类型校验->validators列表中的校验规则从前往后依次验证->从后往前依次验证min_length,max_value等其他规则->校验器内部单字段校验规则->to_internal_value调用结束->校验器内部多字段联合校验规则validate方法
2. to_representation方法
def to_representation(self, instance):
2.1 to_representation方法是所有字段开始进行序列化输出的入口方法,最先被调用
2.2 可以在序列化输出之前对字段值进行定制改造,改造后再返回
3.save
3.1 先看下类视图中的处理逻辑
# projects/views.py
import json
from django.http import HttpResponse, JsonResponse
# 子应用视图
from django.views import View
from projects import models
from projects.serializers import ProjectSerializer
class JsonDecoderError111(BaseException):
pass
class ProjectsView(View):
"""
类视图
:param View: 继承自from django.views import View
:return: HttpResponse对象
"""
def get(self, request):
# 查询所有项目信息
# GET /projects/
projects_list = []
qs = models.Projects.objects.all()
# for item in qs:
# projects_list.append(
# {
# 'id': item.id,
# 'name': item.full_name,
# 'leader': item.leader,
# 'create_time': item.create_time,
# 'update_time': item.update_time,
# }
# )
serializer = ProjectSerializer(instance=qs, many=True)
return JsonResponse(serializer.data, safe=False)
def post(self, request):
# 新建项目
# POST /projects/ json格式参数
try:
python_data = json.loads(request.body)
except:
return JsonResponse({'msg': '参数有误'}, status=400)
serializer = ProjectSerializer(data=python_data)
# 需要调用序列化器serializer的is_valid()方法才能开始校验输入数据
if not serializer.is_valid():
return JsonResponse({'msg': serializer.errors}, status=501)
# 校验通过才创建项目
pro_obj = models.Projects.objects.create(**serializer.validated_data)
return JsonResponse(serializer.validated_data, safe=False, status=201)
class ProjectDetailView(View):
def get(self, request, pk):
# 查询指定项目
# GET /projects/<int:pk>/
pro_obj = models.Projects.objects.get(id=pk)
serializer = ProjectSerializer(instance=pro_obj)
return JsonResponse(serializer.data, status=203)
def put(self, request, pk):
# 修改项目
# PUT /projects/<int:pk>/ json格式参数
try:
python_data = json.loads(request.body)
except:
return JsonResponse({'msg': '参数有误1'}, status=400)
serializer = ProjectSerializer(data=python_data)
if not serializer.is_valid():
return JsonResponse({'msg': serializer.errors}, status=400)
count = models.Projects.objects.filter(id=pk).update(**serializer.validated_data)
result = {
'data': serializer.validated_data,
'msg': '更新成功',
'count': count,
}
return JsonResponse(result, status=203)
def delete(self, request, pk):
# 删除项目
# DELETE /projects/<int:pk>
status = models.Projects.objects.filter(id=pk).delete()
result = {
'msg': f'删除{pk}成功',
'count': status,
}
return JsonResponse(result, safe=False, status=203)
从代码中可以看到,post方法和update方法是有很多重复的代码的,部分重复的代码可以在序列化器中进行封装,这样使用同一个序列化器的地方,就可以直接调用封装的方法.
3.2 views.py中的类视图中在调用ProjectSerializer序列化器类时,
可以同时给参数instance和data传值
3.2.1 若只给data传值,未给instance传值
说明是反序列化校验的数据是为了创建对象,不是为了更新对象
3.2.2 若同时给instance和data传值
说明是为了给instance指定的对象更新数据
3.2.3 序列化器对象创建后,必须在调用is_valid()方法通过,才能使用序列化器对象.data属
性,来获取序列化输出的数据(内部过程:会把validated_data数据作为数据源,自动去
参照序列化器内部定义的字段,对比生成可以序列化输出的模型对象)
3.2.4 serializer.save()方法可传任意参数,若传递的参数与前端传递过来反序列化校验的
数据的key值一致,则会将前端的数据覆盖,在序列化器内部的create方法中可以将
save(myname='xx',age=xx)过滤pop出来,这样不会应为save()方法传递的参数导致
反序列化校验失败了,而且还能在create方法中得到其他想要的数据,适应场景:特定
权限的用户才能创建用户,这里可以将用户信息或权限通过save()方法传递给create
方法判断.
4.create
当类视图中的序列化器对象创建时,若只指定了data参数值,则会调用序列化器类中的create()方法创建对象
def create(self, validated_data: dict):
"""
序列化器类中定义create方法,视图中调用save()方法时,若只给serializer传了data参数的值,
则会自动调用此方法
:param validated_data: 反序列化已经校验通过数据
:return: 模型对象
"""
myname = validated_data.pop('myname')
age = validated_data.pop('age')
pro_obj = Projects.objects.create(**validated_data)
return pro_obj
5.update
当类视图中的序列化器对象创建时,若同时指定了instance参数和data参数值,则会调用序列化器类中的update()方法更新对象
def update(self, instance, validated_data):
"""
序列化器类中定义update方法,视图中调用save()方法时,若给serializer同时传了instance和data参数的值,
则会自动调用此方法
:param instance: 待更新数据的对象
:param validated_data: 待更新的具体数据
:return: 更新数据后的对象
"""
instance.full_name = validated_data.get('full_name') or instance.full_name
instance.leader = validated_data.get('leader') or instance.leader
instance.is_execute = validated_data.get('is_execute') or instance.is_execute
# 更新后通过.save()方法保存生效
instance.save()
return instance
输出
更新前:
更新后:
创建序列化器对象总结:
1. 只传递instance参数:
a.调用is_valid(),errors,validated_data都会报错.
b.不能调用save()方法
c.调用data属性,可以进行序列化输出
2.只传递data参数:
a.必须调用is_valid()方法对数据进行校验,调用errors,validated_data不会报错.
b.调用save()方法会指定调用序列化器类的create()方法
c.调用data属性,可以进行序列化输出(如果有调用save()方法,并且create方法有返回模型
对象的话,那么会把模型对象作为data属性序列化器输出的源数据;如果没有调用
save()方法,那么会把validated_data作为data属性序列化输出的源数据)
3.同时传递instance参数和data参数
a.必须调用is_valid()方法对数据进行校验,调用errors,validated_data不会报错.
b.调用save()方法会指定调用序列化器类的update()方法
c.调用data属性,可以进行序列化输出(如果有调用save()方法,并且update方法有返回模型
对象的话,那么会把模型对象作为data属性序列化器输出的源数据;如果没有调用
save()方法,那么会把validated_data作为data属性序列化输出的源数据)
附代码:
# projects/views.py
import json
from django.http import HttpResponse, JsonResponse
# 子应用视图
from django.views import View
from projects import models
from projects.serializers import ProjectSerializer
class JsonDecoderError111(BaseException):
pass
class ProjectsView(View):
"""
类视图
:param View: 继承自from django.views import View
:return: HttpResponse对象
"""
def get(self, request):
# 查询所有项目信息
# GET /projects/
qs = models.Projects.objects.all()
serializer = ProjectSerializer(instance=qs, many=True)
return JsonResponse(serializer.data, safe=False)
def post(self, request):
# 新建项目
# POST /projects/ json格式参数
try:
python_data = json.loads(request.body)
except:
return JsonResponse({'msg': '参数有误'}, status=400)
serializer = ProjectSerializer(data=python_data)
# 需要调用序列化器serializer的is_valid()方法才能开始校验输入数据
if not serializer.is_valid():
return JsonResponse({'msg': serializer.errors}, status=501)
# 校验通过才创建项目
# pro_obj = models.Projects.objects.create(**serializer.validated_data)
# save()方法优化53行代码
serializer.save(myname='小白', age=18)
return JsonResponse(serializer.validated_data, safe=False, status=201)
class ProjectDetailView(View):
def get(self, request, pk):
# 查询指定项目
# GET /projects/<int:pk>/
pro_obj = models.Projects.objects.get(id=pk)
serializer = ProjectSerializer(instance=pro_obj)
return JsonResponse(serializer.data, status=203)
def put(self, request, pk):
# 修改项目
# PUT /projects/<int:pk>/ json格式参数
try:
python_data = json.loads(request.body)
except:
return JsonResponse({'msg': '参数有误1'}, status=400)
# 获取待更新的对象
pro_obj = models.Projects.objects.get(id=pk)
serializer = ProjectSerializer(instance=pro_obj, data=python_data)
if not serializer.is_valid():
return JsonResponse({'msg': serializer.errors}, status=400)
# count = models.Projects.objects.filter(id=pk).update(**serializer.validated_data)
# result = {
# 'data': serializer.validated_data,
# 'msg': '更新成功',
# 'count': count,
# }
# save()方法优化82~87行代码
serializer.save()
return JsonResponse(serializer.data, status=203)
def delete(self, request, pk):
# 删除项目
# DELETE /projects/<int:pk>
status = models.Projects.objects.filter(id=pk).delete()
result = {
'msg': f'删除{pk}成功',
'count': status,
}
return JsonResponse(result, safe=False, status=203)
# projects/serializers.py
# 此文件定义子应用projects具备的模型类对应的序列化器
from rest_framework import serializers
from rest_framework.validators import UniqueValidator
from interfaces.models import Interfaces
from projects.models import Projects
class InterfacesSerializer(serializers.Serializer):
"""自定义的序列化器类实际上是Field的子类"""
id = serializers.IntegerField(label='接口id', help_text='接口名称', read_only=True)
name = serializers.CharField(label='接口名称', help_text='接口名称',
max_length=50, min_length=2)
tester = serializers.CharField(label='接口测试人员', help_text='接口测试人员',
max_length=50, min_length=2)
projects = serializers.CharField(label='接口所属项目id', help_text='接口所属项目id',
read_only=True)
def is_contain_keyword(values: str):
"""
定义一个校验规则,判断字段是否以'xx项目'结尾
:param values: 序列化器中待校验的字段
:return:
"""
# 如果校验失败,要raise serializers.ValidationError异常,并可以指定异常信息提示
if not values.endswith('项目'):
raise serializers.ValidationError("项目名称必须以'项目'结尾")
# 如果校验成功,不做任何处理,接着往下校验
pass
class ProjectSerializer(serializers.Serializer):
"""
"""
id = serializers.IntegerField(label='项目id', help_text='项目id',
read_only=True)
full_name = serializers.CharField(label='项目名称', help_text='项目名称', max_length=20, min_length=4,
error_messages={"max_length": "项目名称不能超过20个字符",
"min_length": "项目名称不能小于4个字符"},
validators=[UniqueValidator(queryset=Projects.objects.all(),
message='项目名称不能重复'),
is_contain_keyword]
)
leader = serializers.CharField(label='项目负责人', help_text='项目负责人', max_length=20, min_length=2)
is_execute = serializers.BooleanField(label='项目是否执行', help_text='项目是否执行', required=False)
desc = serializers.CharField(label='项目描述', help_text='项目描述', allow_null=True, allow_blank=True)
create_time = serializers.DateTimeField(label='项目从创建时间', help_text='项目创建时间',
format='%Y-%m-%d %H:%M:%S', read_only=True)
update_time = serializers.DateTimeField(label='项目跟新时间', help_text='项目更新时间',
read_only=True)
# 将指定的从表序列化器类作为interfaces_set以返回多个字段值,因为InterfacesSerializer类也是Field的子类,所以可以作为字段属性
interfaces_set = InterfacesSerializer(label='所属接口信息', help_text='所属接口信息',
read_only=True, many=True)
def validate_full_name(self, attr: str):
"""
自定义单字段校验规则:validate_xxx
1。若校验失败,跟序列化器类外部定义的校验方法一样raise serializers.ValidationError()
2。若校验成功,则需要return xxx,这个xxx会赋值给被校验的字段full_name
:param attr: 待校验值
:return: attr
"""
if not attr.startswith('春田'):
raise serializers.ValidationError("项目名必须以'春田'开头")
return attr
def validate(self, attrs: dict):
"""
自定义多字段校验规则:validate,例如注册模块的输入密码与确认密码功能,会用到多字段联合校验
1。若校验失败,跟序列化器类外部定义的校验方法一样raise serializers.ValidationError()
2。若校验成功,则需要return xxx,这个xxx会赋值给被校验的字段
:param attrs: 待校验的多个关联字段
:return: attrs
"""
if not attrs.get("full_name").startswith("春田") or not attrs.get('is_execute'):
raise serializers.ValidationError("项目名必须以'春田'开头 或者 is_execute为True")
return attrs
def to_internal_value(self, data):
"""
1.to_internal_value方法是所有字段开始进行反序列化输入并校验的入口方法,最先被调用
2.可在对各单个字段校验结束后,return tmp之前对数据进行定制化修改
:param data:
:return:
"""
tmp = super().to_internal_value(data=data)
return tmp
def to_representation(self, instance):
"""
1.to_representation方法是所有字段开始进行序列化输出的入口方法,最先被调用
2.可以在序列化输出之前对字段值进行定制改造,改造后再返回
:param instance:
:return:
"""
tmp = super().to_representation(instance=instance)
return tmp
def create(self, validated_data: dict):
"""
序列化器类中定义create方法,视图中调用save()方法时,若只给serializer传了data参数的值,
则会自动调用此方法
:param validated_data: 反序列化已经校验通过数据
:return: 模型对象
"""
myname = validated_data.pop('myname')
age = validated_data.pop('age')
pro_obj = Projects.objects.create(**validated_data)
return pro_obj
def update(self, instance, validated_data):
"""
序列化器类中定义update方法,视图中调用save()方法时,若给serializer同时传了instance和data参数的值,
则会自动调用此方法
:param instance: 待更新数据的对象
:param validated_data: 待更新的具体数据
:return: 更新数据后的对象
"""
instance.full_name = validated_data.get('full_name') or instance.full_name
instance.leader = validated_data.get('leader') or instance.leader
instance.is_execute = validated_data.get('is_execute') or instance.is_execute
# 更新后通过.save()方法保存生效
instance.save()
return instance