一、通过Serializer类实现序化器
1、序列化输出示例:
class Project(models.Model): """项目表""" objects = models.Manager() name =models.CharField(max_length=32,verbose_name="项目名称",null=False) desc = models.CharField(max_length=64,verbose_name="项目描述") status = models.BooleanField(verbose_name="状态",default=True) created_time = models.DateTimeField('创建日期', auto_now = True) def __str__(self): return self.name
from rest_framework import serializers class ProjectsSerializer(serializers.Serializer): name =serializers.CharField(max_length=32,label="项目名称") desc = serializers.CharField(max_length=64,label="项目描述") status = serializers.BooleanField(label="状态",default=True) created_time = serializers.DateTimeField(label='创建日期')
#序列化操作示例 class ProjcetsViews(View): def get(self,request,pk): projects = Project.objects.get(pk=pk) serializer = ProjectsSerializer(instance=projects) return JsonResponse(serializer.data) def get(self,request): projects = Project.objects.all() serializer = ProjectsSerializer(instance=projects,many=True) return JsonResponse(serializer.data,safe=False)
2、反序列化、校验前端数据:
def post(self, request): """创建项目""" data = request.body.decode("utf-8") # 接收到的是自己序列,需要反序列化成python对象 python_data = json.loads(data) # 生成序列化对象,传参给data参数 serializer = ProjectsSerializer(data=python_data) # 根据模型中定义的字段属性,用is_valid方法校验,raise_exception参数决定是否抛出异常 if serializer.is_valid(): # 校验通过后,通过validated_data属性获取校验过后的参数 param = serializer.validated_data # 创建model对象保存到数据库 obj = Project.objects.create(**param) # 将创建的对象序列化后,返回给前端 obj_serializer = ProjectsSerializer(instance=obj) return JsonResponse(obj_serializer.data) else: # 校验失败,通过errors属性获取错误信息 return JsonResponse(serializer.errors) return JsonResponse({"result": True})
校验通过、不通过示例:
3、校验某个字段
自定义校验器:
# 自定义校验器 # 第一个参数为字段值 def project_name_is_valid(name): if "项目" not in name: raise serializers.ValidationError(detail="项目名称必须包含'项目'", code=10001) class ProjectsSerializer(serializers.Serializer): name = serializers.CharField(max_length=32, label="项目名称", validators=[UniqueValidator(queryset=Project.objects.all(), message="项目名称不能重复"), project_name_is_valid]) desc = serializers.CharField(max_length=64, label="项目描述") status = serializers.BooleanField(label="状态", default=True)
钩子函数方式定义校验器:
from rest_framework import serializers from rest_framework.validators import UniqueValidator from personal.models import Project # 自定义校验器 # 第一个参数为字段值 def project_name_is_valid(name): if "项目" not in name: raise serializers.ValidationError(detail="项目名称必须包含'项目'", code=10001) class ProjectsSerializer(serializers.Serializer): name = serializers.CharField(max_length=32, label="项目名称", validators=[UniqueValidator(queryset=Project.objects.all(), message="项目名称不能重复"), project_name_is_valid]) desc = serializers.CharField(max_length=64, label="项目描述") status = serializers.BooleanField(label="状态", default=True) # read_only=True只做序列化输出 created_time = serializers.DateTimeField(label='创建日期', read_only=True) # 单字段校验,validate_字段名称,参数为字段值 # 校验通过后,需要返回字段值 # 不需要显示调用 def validate_name(self, value): if not value.endswith("项目"): raise serializers.ValidationError("项目名称必须以'项目'结尾") return value # 多字段联合校验 # 函数名称固定为validate,attrs为包含所有字段名称和值的字典 # 校验成功后,返回attrs # 项目名称或者描述中必须包含"test" def validate(self, attrs): if 'test' not in attrs["name"] and 'test' not in attrs["desc"]: raise serializers.ValidationError("项目名称或者描述中必须包含'test'") return attrs
校验顺序:按照字段定义时从左到右的顺序:字段类型-字段长度-validators列表中的校验器-validate_name-多字段校验valitate
4、在序列化器中定义数据库操作方法
# 视图类中的POST(创建),PUT(更新操作)
# 序列化操作示例 class ProjcetsViews(View): def get(self, request, pk): projects = Project.objects.get(pk=pk) serializer = ProjectsSerializer(instance=projects) return JsonResponse(serializer.data) def get(self, request): projects = Project.objects.all() serializer = ProjectsSerializer(instance=projects, many=True) return JsonResponse(serializer.data, safe=False) def post(self, request): """创建项目""" data = request.body.decode("utf-8") # 接收到的是自己序列,需要反序列化成python对象 python_data = json.loads(data) # 生成序列化对象,传参给data参数 serializer = ProjectsSerializer(data=python_data) # 根据模型中定义的字段属性,用is_valid方法校验,raise_exception参数决定是否抛出异常 if serializer.is_valid(): # 校验通过后,通过validated_data属性获取校验过后的参数 param = serializer.validated_data # 创建model对象保存到数据库 # obj = Project.objects.create(**param) serializer.save() # 将创建的对象序列化后,返回给前端 # obj_serializer = ProjectsSerializer(instance=obj) return JsonResponse(serializer.data) else: # 校验失败,通过errors属性获取错误信息 return JsonResponse(serializer.errors) return JsonResponse({"result": True}) def put(self, request, pk): """修改项目""" project = Project.objects.get(pk=pk) param = request.body.decode("utf-8") python_data = json.loads(param) # 序列化时给data传参,调用save方法时,实际上调用的是序列化器的create方法 # 序列化时给data、instance传参,调用save方法时,实际上调用的是序列化器的update方法 serializer = ProjectsSerializer(instance=project, data=python_data) try: serializer.is_valid(raise_exception=True) except: return JsonResponse(serializer.errors) serializer.save() return JsonResponse(serializer.data)
from rest_framework import serializers from rest_framework.validators import UniqueValidator from personal.models import Project # 自定义校验器 # 第一个参数为字段值 def project_name_is_valid(name): if "项目" not in name: raise serializers.ValidationError(detail="项目名称必须包含'项目'", code=10001) class ProjectsSerializer(serializers.Serializer): name = serializers.CharField(max_length=32, label="项目名称", validators=[UniqueValidator(queryset=Project.objects.all(), message="项目名称不能重复"), project_name_is_valid]) desc = serializers.CharField(max_length=64, label="项目描述") status = serializers.BooleanField(label="状态", default=True) # read_only=True只做序列化输出 created_time = serializers.DateTimeField(label='创建日期', read_only=True) # 单字段校验,validate_字段名称,参数为字段值 # 校验通过后,需要返回字段值 # 不需要显示调用 def validate_name(self, value): if not value.endswith("项目"): raise serializers.ValidationError("项目名称必须以'项目'结尾") return value # 多字段联合校验 # 函数名称固定为validate,attrs为包含所有字段名称和值的字典 # 校验成功后,返回attrs # 项目名称或者描述中必须包含"test" def validate(self, attrs): if 'test' not in attrs["name"] and 'test' not in attrs["desc"]: raise serializers.ValidationError("项目名称或者描述中必须包含'test'") return attrs # 重写实现新增操作 # validated_data为序列器验证通过后的字典类型数据 def create(self, validated_data): return Project.objects.create(**validated_data) # 重写实现更新操作 # instance为要更新的对象,validated_data为序列器校验通过后的参数 def update(self, instance, validated_data): instance.name = validated_data["name"] instance.desc = validated_data["desc"] instance.status = validated_data["status"] instance.save() return instance
思考:为啥序列化器调用save方法的时候,能分别调用create、update方法呢
1、我们自定义的序列化器继承了序列化类:Serializer
2、Serializer类继承了:BaseSerializer类
3、在BaseSerializer类中关于create、update、save的方法如下:
def update(self, instance, validated_data): raise NotImplementedError('`update()` must be implemented.') def create(self, validated_data): raise NotImplementedError('`create()` must be implemented.') def save(self, **kwargs): assert not hasattr(self, 'save_object'), ( 'Serializer `%s.%s` has old-style version 2 `.save_object()` ' 'that is no longer compatible with REST framework 3. ' 'Use the new-style `.create()` and `.update()` methods instead.' % (self.__class__.__module__, self.__class__.__name__) ) assert hasattr(self, '_errors'), ( 'You must call `.is_valid()` before calling `.save()`.' ) assert not self.errors, ( 'You cannot call `.save()` on a serializer with invalid data.' ) # Guard against incorrect use of `serializer.save(commit=False)` assert 'commit' not in kwargs, ( "'commit' is not a valid keyword argument to the 'save()' method. " "If you need to access data before committing to the database then " "inspect 'serializer.validated_data' instead. " "You can also pass additional keyword arguments to 'save()' if you " "need to set extra attributes on the saved model instance. " "For example: 'serializer.save(owner=request.user)'.'" ) assert not hasattr(self, '_data'), ( "You cannot call `.save()` after accessing `serializer.data`." "If you need to access data before committing to the database then " "inspect 'serializer.validated_data' instead. " ) validated_data = dict( list(self.validated_data.items()) + list(kwargs.items()) ) if self.instance is not None: self.instance = self.update(self.instance, validated_data) assert self.instance is not None, ( '`update()` did not return an object instance.' ) else: self.instance = self.create(validated_data) assert self.instance is not None, ( '`create()` did not return an object instance.' ) return self.instance
从上述源码中可以看出:
1、必须在自定义序列器中显示create、update方法,否则对象在调用的时候会调用父类的方法,抛出NotImplementedError异常
2、save方法解释了什么情况下调用create、update方法:
3、update、create方法都需要将创建、修改的对象返回
二、通过ModelSerializer类实现序列化器
class ProjectModelSerializer(serializers.ModelSerializer): # 重新定义字段属性,覆盖自动生成的,比如添加自定义的校验器 name = serializers.CharField(max_length=32, label="项目名称", validators=[UniqueValidator(queryset=Project.objects.all(), message="项目名称不能重复"), project_name_is_valid], error_messages={"max_length": "名称不能超过32个字节"}) # 单字段、多字段校验一样的需要手动实现 # 单字段校验,validate_字段名称,参数为字段值 # 校验通过后,需要返回字段值 # 不需要显示调用 def validate_name(self, value): if not value.endswith("项目"): raise serializers.ValidationError("项目名称必须以'项目'结尾") return value # 多字段联合校验 # 函数名称固定为validate,attrs为包含所有字段名称和值的字典 # 校验成功后,返回attrs # 项目名称或者描述中必须包含"test" def validate(self, attrs): if 'test' not in attrs["name"] and 'test' not in attrs["desc"]: raise serializers.ValidationError("项目名称或者描述中必须包含'test'") return attrs class Meta: # 指定参考哪个模型来创建序列化器 modle = Project # 指定为模型类的哪些字段来生成序列化器 # 所有字段,其中主键为加上read_only=True fields = "__all__" # 指定部分字段 # fields = ("name","desc") # 排除部分字段 # exclude = ("id") # 定义只序列化输出的、不反序列化输入的字段 # read_only_fields = ("status",) # 为字段添加额外的属性 extra_kwargs = { 'name': { 'write_only': True, "error_messages": { "max_length": "名称最大长度不能超过32个字节" } } }
基本用法见代码中注释,序列化和反序列与方式一一致,主要是对方式一的一些简化
另外,ModelSerializer类已经实现了create、update方法,不用自己写