前言
在 Django REST framework 中,数据序列化至关重要。本文将探讨 普通序列化器 和 模型序列化器,了解它们的基本功能和差异,帮助您根据项目需求选择合适的序列化器。
Response是不能直接返回ORM数据的,所以需要我们进行序列化操作,可以通过手动将其转为字典或JSON,也可以使用DRF所提供的序列化器,一般建议使用序列化器。
如果你经常使用的是自己去将数据封装为JSON,那么常见的代码模型就像这样
data = models.objects.all() json_data = {} for d in data: json_data['age'] = d.age json_data['name'] = d.name return Response(json_data)
随字段越来越多,工作量会越来越大,而且有关于时间(DateTimeField、DateField)等字段类型的序列化直接通过JSON也是不行的,需要自己手动编写JSON的序列化器,非常麻烦,于是乎 DRF 就提供了更为便捷的两种序列化器,普通序列化器与模型序列化器
一、普通序列化器-Serializer
1. 普通序列化器编写方式
导包:
from rest_framework import serializers
普通序列化器,可以按照给定字段,将所匹配的ORM数据字段转换为JSON数据,不光可以对一条数据,也可以对一个QuerySet所对应的结果集
例如:
用户表 UserModel:
#models.py from django.db import models # Create your models here. class UserModel(models.Model): name = models.CharField(max_length=50) phone = models.CharField(max_length=11) password = models.CharField(max_length=30) info = models.CharField(max_length=100, null=True) def __str__(self): return self.name class Meta: db_table = 'user'
普通序列化器UserSerializer定义如下:
#userSerializer.py class UserSerializer(serializers.Serializer): name = serializers.CharField(max_length=50) phone = serializers.CharField(validators=[validators_phone]) password = serializers.CharField(max_length=30) info = serializers.CharField(max_length=100,default="默认值")
序列化器的使用分两个阶段:
1、在客户端请求时,使用序列化器可以完成对数据的反序列化(将字典格式的数据转化为模型对象)。
2、在服务器响应时,使用序列化器可以完成对数据的序列化(将模型对象转化为字典格式的数据)。
2. 普通序列化器序列化
序列化就是将ORM数据放入序列化器加工,诞生出JSON数据对象,序列化器对象的data
属性即为处理好的 JSON 数据对象
1、单条数据的序列化:
- 单挑数据的序列化很简单,直接通过序列化器类对象的参数
instance
传入查询得到的结果即可
#views.py class UserIdView(APIView): def get(self, request, id): user = UserModel.objects.get(pk=id) usSer = UserSerializer(instance=user) return Response({"message": "get测试成功!", "data": usSer.data})
2、多条数据的序列化:
- 如果使用像filter、all这样的一些ORM方法,获取到的是QuerySet结果集,不是单独数据对象,那么使用序列化器时,需要传入many=True参数,用来表示:传入的不止一条数据。
#views.py class UserView(APIView): def get(self, request): users = UserModel.objects.all() usSer = UserSerializer(instance=users, many=True) return Response({"message":"get测试成功!","data":usSer.data})
Serializer属性中选项参数
选项参数名称 | 作用 |
max_length | 最大长度 |
min_length | 最小长度 |
allow_blank | 是否允许为空 |
trim_whitespace | 是否截断空白字符 |
max_value | 最大值 |
min_value | 最小值 |
通用参数名称 | 作用 |
read_only | 该字段仅用于序列化输出,需要序列化输出时设置:read_only=True;默认为False |
write_only | 该字段仅用于反序列输入,需要序列化输入时设置:write_only=True;默认为False |
required | 该字段表示在反序列化输入时必须输入 |
default | 反序列化时使用的默认值 |
allow_null | 表明该字段是否允许传入None,默认False |
validators | 对字段进行校验,定义在字段中 |
error_message | 当字段校验不通过时,报error_message的value值 |
label | 用于HTML展示API页面时,显示的字段名称 |
help_text | 用于HTML展示API页面时,显示的字段帮助提示信息 |
3. 普通序列化器反序列化创建
反序列化的概念很简单,就是把
JSON
等数据变为ORM
数据对象,甚至是入库或者是修改DRF要求序列化器必须对数据进行校验,才能获取验证成功的数据或保存成模型类对象
- 在操作过程中,反序列化首先需要通过
data
传参- 接着调用
is_valid
进行校验,验证成功返回True
,反之返回False
- 如果校验失败,还可以通过结果的
errors
属性返回错误值is_valid
调用后方法会进行字段属性(max_value=10)
的校验、自定义的校验等等
- 对校验过后的对象调用
save
方法,这个save
方法会触发序列化器中的create
方法
- 普通序列化器中,
create
方法默认是没有实现的,需要手动根据模型类进行编写如果需要自定义校验规则,可以通过
validators
实现:
#userSerializer.py from rest_framework import serializers from app.models import UserModel import re def validators_phone(values): r_phone = r"^1[3-9]\d{9}$" if re.match(r_phone, values): print("手机号匹配成功!") else: print("手机号匹配失败,抛出异常!") raise serializers.ValidationError("手机号匹配失败!不满足规则!") class UserSerializer(serializers.Serializer): name = serializers.CharField(max_length=50) phone = serializers.CharField(validators=[validators_phone]) password = serializers.CharField(max_length=30) info = serializers.CharField(max_length=100,default="默认值")
比如现在,需要提交数据用到创建User的接口,此时可以这么做
为了能够保证数据成功入库,默认的普通序列化器是不具备入库功能的,需要编写
create
方法
#userSerializer.py class UserSerializer(serializers.Serializer): name = serializers.CharField(max_length=50) phone = serializers.CharField(validators=[validators_phone]) password = serializers.CharField(max_length=30) info = serializers.CharField(max_length=100,default="默认值") def create(self, validated_data): object = UserModel.objects.create(**validated_data) return object #具体来说,**validated_data的作用是:解包字典。 #它将validated_data字典中的键值对解包为一系列的关键字参数。
成功之后,就可以通过像之前一样的数据提交,编写视图完成数据入库,序列化器可以直接处理request所提交的数据data,并且可以剔除在request.data中其他多余的字段,只会处理序列化器里的字段
# views.py class UserView(APIView): def post(self, request): ser = UserSerializer(data=request.data) # 传参data,进行反序列化 if ser.is_valid(): print("校验成功!") ser.save() return Response({"message":"[POST]信息添加成功!"}) else: print("校验失败!") return Response({"message": ser.errors})
4. 普通序列化器反序列化更新
反序列化经过校验的数据,不光可以用来创建数据,还可以用来更新数据
- 更新首先需要一个已经存在的数据,所以需要通过
instance
参数传递已有的一个ORM对象- 还需要待更新的新值,那么就需要传
data
参数- 之后同样需要
is_valid
方法调用,检查即将更新进入的数据是否合法- 最终
save
触发序列化器中的update
方法默认普通序列化器是没有自带对于数据的更新方法的,现在需要在序列化器里创建
update
方法
# userSerializer.py class UserSerializer(serializers.Serializer): name = serializers.CharField(max_length=50) phone = serializers.CharField(validators=[validators_phone]) password = serializers.CharField(max_length=30) info = serializers.CharField(max_length=100,default="默认值") def update(self, instance, validated_data): # instance 要更新的数据,validated_data 是新数据 instance.name = validated_data.get('name', instance.name) instance.phone = validated_data.get('phone', instance.phone) instance.password = validated_data.get('password', instance.password) instance.info = validated_data.get('info', instance.info) instance.save() return instance #获取字段值: #validated_data.get('name') 尝试从 validated_data 字典中获取键为 'name' 的值。 #validated_data 是由序列化器在验证请求数据后生成的一个字典,它包含了经过验证的字段和它们的值。 #默认值机制: #get 方法有一个可选的第二个参数,即默认值。如果 'name' 这个键不存在于validated_data 中,get 方法将返回这个默认值。 #在这个例子中,如果请求数据中没有包含 'name' 字段,那么默认值就是 instance.name,即当前模型实例的 name 字段的值。
然后通过PUT
传递要更新数据的ID
,以及更新后的值,来为某条数据更新
class UserIdView(APIView): def put(self, request, id): user = UserModel.objects.get(pk=id) ser = UserSerializer(instance=user, data=request.data) if ser.is_valid(): print("校验成功!") ser.save() return Response({"message": "[PUT]信息修改成功!"}) else: print("校验失败!") return Response({"message": ser.errors})
5. 普通序列化器完整代码
models.py:
from django.db import models # Create your models here. class UserModel(models.Model): name = models.CharField(max_length=50) phone = models.CharField(max_length=11) password = models.CharField(max_length=30) info = models.CharField(max_length=100, null=True) def __str__(self): return self.name class Meta: db_table = 'user'
userSerializer.py:
from rest_framework import serializers from app.models import UserModel import re def validators_phone(values): r_phone = r"^1[3-9]\d{9}$" if re.match(r_phone, values): print("手机号匹配成功!") else: print("手机号匹配失败,抛出异常!") raise serializers.ValidationError("手机号匹配失败!不满足规则!") class UserSerializer(serializers.Serializer): name = serializers.CharField(max_length=50) phone = serializers.CharField(validators=[validators_phone]) password = serializers.CharField(max_length=30) info = serializers.CharField(max_length=100,default="默认值") def create(self, validated_data): object = UserModel.objects.create(**validated_data) return object def update(self, instance, validated_data): # instance 要更新的数据,validated_data 是新数据 instance.name = validated_data.get('name', instance.name) instance.phone = validated_data.get('phone', instance.phone) instance.password = validated_data.get('password', instance.password) instance.info = validated_data.get('info', instance.info) instance.save() return instance
views.py:
from rest_framework.views import APIView from rest_framework.response import Response from app.models import UserModel from app.serializer.userSerializer import UserSerializer from django.shortcuts import render # Create your views here. class UserView(APIView): def get(self, request): users = UserModel.objects.all() usSer = UserSerializer(instance=users, many=True) return Response({"message":"get测试成功!","data":usSer.data}) def post(self, request): ser = UserSerializer(data=request.data) # 传参data,进行反序列化 if ser.is_valid(): print("校验成功!") ser.save() return Response({"message":"[POST]信息添加成功!"}) else: print("校验失败!") return Response({"message": ser.errors}) class UserIdView(APIView): def get(self, request, id): user = UserModel.objects.get(pk=id) usSer = UserSerializer(instance=user) return Response({"message": "get测试成功!", "data": usSer.data}) def put(self, request, id): user = UserModel.objects.get(pk=id) ser = UserSerializer(instance=user, data=request.data) if ser.is_valid(): print("校验成功!") ser.save() return Response({"message": "[PUT]信息修改成功!"}) else: print("校验失败!") return Response({"message": ser.errors})
urls.py:
from django.urls import path from app.views import UserView,UserIdView urlpatterns = [ path('user/', UserView.as_view()), path('user/<int:id>/', UserIdView.as_view()), ]
二、模型序列化器-ModelSerializer
1. 模型序列化器编写方式
之前的普通序列化器,很明显可以感觉到,如果模型类字段少了,还行,但是模型字段越来越多,那么开发者在序列化器里所要复刻的字段也要越来越多,很麻烦, 而且还得手动实现
update
和create
方法,而且光写了序列化器字段还不行,还得有字段属性
于是乎,有了现在的与模型类关联的序列化器,可以更加方便的进行字段映射以及内置方法的编写
模型类关联序列化器大概总结有如下三个特性,一个缺点:
- 特点:
- 基于模型类自动生成一系列字段
- 自动生成的系列字段,同时还包含
unique
、max_length
等属性校验- 包含默认的
create
和update
的实现
- 缺点:
- 不会自动映射模型类字段的
default
属性
模型类关联的序列化器用的是新的序列化器基类:
from rest_framework.serializers import ModelSerializer
用户模型类依旧使用上文中的UserModel.py文件
按照之前的普通序列化写法,你需要同步一个字段,并将字段属性也要记得同步,非常麻烦,但通过与模型类关联的序列化器就很简单了。
- 首先通过继承
ModelSerializer
基类- 通过序列化器元类属性中的
model
属性关联模型类- 通过序列化器元类属性中的
fields
属性指明序列化器需要处理的字段
# userModelSerializer.py from rest_framework import serializers from app.models import UserModel class UserModelSerializer(serializers.ModelSerializer): # 不需要再重写 create 和 update 方法了,可查看ModelSerializer源码 class Meta: model = UserModel fields = '__all__' # 指明所有模型类字段 # exclude = ('password',) # 排除掉的字段 # read_only_fields = ('name','info') # 只用于序列化的字段 # fields = ('name','phone','password','info') # extra_kwargs = { # 'info':{'min_length':5, 'required':True}, # } #修改原有字段的选项参数
模型类关联的序列化器和普通的序列化器使用方法一样,使用序列化器返回当前所有的商品数据,还是像之前一样传入instance参数即可,还要记得由于是多个商品,不是单独数据,要记得加many=True参数
2. 模型序列化器反序列化创建、更新
模型序列化器的创建就更简单了,不需要手动实现create方法,大致流程如下:
- 为序列化器绑定数据,
ser=Serializer(data=request.data)
- 校验数据,
ser.is_valid()
- 存储入库,
ser.save()
创建用户接口:
from rest_framework.views import APIView from rest_framework.response import Response from app.models import UserModel from app.serializer.userModelSerializer import UserModelSerializer # Create your views here. class UserView(APIView): def get(self, request): users = UserModel.objects.all() usSer = UserModelSerializer(instance=users, many=True) return Response({"message":"get测试成功!","data":usSer.data}) def post(self, request): ser = UserModelSerializer(data=request.data) # 传参data,进行反序列化 if ser.is_valid(): print("校验成功!") ser.save() return Response({"message":"[POST]信息添加成功!"}) else: print("校验失败!") return Response({"message": ser.errors})
注意: 反序列化自动生成的字段属性中,不会包含原始模型类字段中的default字段属性
更细用户信息接口:
更新某一个商品数据,模型序列化器也是自带了
update
方法
class UserIdView(APIView): def get(self, request, id): user = UserModel.objects.get(pk=id) usSer = UserModelSerializer(instance=user) return Response({"message": "get测试成功!", "data": usSer.data}) def put(self, request, id): user = UserModel.objects.get(pk=id) ser = UserModelSerializer(instance=user, data=request.data) if ser.is_valid(): print("校验成功!") ser.save() return Response({"message": "[PUT]信息修改成功!"}) else: print("校验失败!") return Response({"message": ser.errors})
3. 模型序列化器与普通序列化器的对比
- 序列化时,将模型类对象传入
instance
参数
- 序列化结果使用序列化器对象的
data
属性获取得到
- 反序列化创建时,将要被反序列化的数据传入
data
参数
- 反序列化一定要记得先使用
is_valid
校验
- 反序列化更新时,将要更新的数据对象传入
instance
参数,更新后的数据传入data
参数 - 模型序列化器比普通序列化器更加方便,自动生成序列化映射字段,
create
、update
方法等 - 关联外键序列化,字段属性外键为多时要记得加
many=True