Serializer
drf中为我们提供了Serializer,他主要有两大功能:
- 对请求数据校验(底层调用Django的Form和ModelForm)
- 对数据库查询到的对象进行序列化
数据校验
示例1:基于Serializer:
示例2:基于ModelSerializer:
# models.py
from django.db import models
class Role(models.Model):
""" 角色表 """
title = models.CharField(verbose_name="名称", max_length=32)
class Department(models.Model):
""" 部门表 """
title = models.CharField(verbose_name="名称", max_length=32)
class UserInfo(models.Model):
""" 用户表 """
level_choices = ((1, "普通会员"), (2, "VIP"), (3, "SVIP"),)
level = models.IntegerField(verbose_name="级别", choices=level_choices, default=1)
username = models.CharField(verbose_name="用户名", max_length=32)
password = models.CharField(verbose_name="密码", max_length=64)
age = models.IntegerField(verbose_name="年龄", default=0)
email = models.CharField(verbose_name="邮箱", max_length=64)
token = models.CharField(verbose_name="TOKEN", max_length=64, null=True, blank=True)
# 外键
depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE)
# 多对多
roles = models.ManyToManyField(verbose_name="角色", to="Role")
提示:save方法会返回新生成的数据对象。
当传输的数据都是不可变对象时,可以通过form-data的格式传递。(如上)
但是当传输的数据包含列表,字典这种时,必须通过json的格式传递。(如下)
示例3:基于ModelSerializer(含FK+M2M):
提示:save方法会返回新生成的数据对象。
序列化
通过ORM从数据库获取到的 QuerySet 或 对象 均可以被序列化为 json 格式数据。
# models.py
from django.db import models
class Role(models.Model):
""" 角色表 """
title = models.CharField(verbose_name="名称", max_length=32)
class Department(models.Model):
""" 部门表 """
title = models.CharField(verbose_name="名称", max_length=32)
class UserInfo(models.Model):
""" 用户表 """
level_choices = ((1, "普通会员"), (2, "VIP"), (3, "SVIP"),)
level = models.IntegerField(verbose_name="级别", choices=level_choices, default=1)
username = models.CharField(verbose_name="用户名", max_length=32)
password = models.CharField(verbose_name="密码", max_length=64)
age = models.IntegerField(verbose_name="年龄", default=0)
email = models.CharField(verbose_name="邮箱", max_length=64, null=True, blank=True)
token = models.CharField(verbose_name="TOKEN", max_length=64, null=True, blank=True)
depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE, null=True, blank=True)
roles = models.ManyToManyField(verbose_name="角色", to="Role")
示例1:序列化基本字段
# 切记, 如果从数据库获取的不是QuerySet对象,而是单一对象,例如:
data_object = modes.UserInfo.objects.filter(id=2).first()
ser = UserModelSerializer(instance=data_object,many=False)
print(ser.data)
示例2:自定义字段
在序列化时:
可以通过source
或者serializers.SerializerMethodField
来定义显示字段的值:
- source
- get_level_display(choice)
- depart.title(外键)
- serializers.SerializerMethodField
- 字段定义serializers.SerializerMethodField
- get_字段名 来序列化数据
示例3:序列化类的嵌套
序列换类可以嵌套使用:
直接通过子弹引用已有的序列化类即可。(要注意多条数据的情况)
数据校验&序列化
上述示例均属于单一功能(要么校验,要么序列化),其实当我们编写一个序列化类既可以做数据校验,也可以做序列化,例如:
# models.py
from django.db import models
class Role(models.Model):
""" 角色表 """
title = models.CharField(verbose_name="名称", max_length=32)
class Department(models.Model):
""" 部门表 """
title = models.CharField(verbose_name="名称", max_length=32)
class UserInfo(models.Model):
""" 用户表 """
level_choices = ((1, "普通会员"), (2, "VIP"), (3, "SVIP"),)
level = models.IntegerField(verbose_name="级别", choices=level_choices, default=1)
username = models.CharField(verbose_name="用户名", max_length=32)
password = models.CharField(verbose_name="密码", max_length=64)
age = models.IntegerField(verbose_name="年龄", default=0)
email = models.CharField(verbose_name="邮箱", max_length=64, null=True, blank=True)
token = models.CharField(verbose_name="TOKEN", max_length=64, null=True, blank=True)
depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE, null=True, blank=True)
roles = models.ManyToManyField(verbose_name="角色", to="Role")
# urls.py
from django.urls import path, re_path, include
from app01 import views
urlpatterns = [
path('api/users/', views.UserView.as_view()),
]
# views.py
from django.core.validators import EmailValidator
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from app01 import models
class DepartModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Department
fields = ['id', "title"]
extra_kwargs = {
"id": {"read_only": False}, # 数据验证
"title": {"read_only": True} # 序列化
}
class RoleModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Role
fields = ['id', "title"]
extra_kwargs = {
"id": {"read_only": False}, # 数据验证
"title": {"read_only": True} # 序列化
}
class UserModelSerializer(serializers.ModelSerializer):
level_text = serializers.CharField(source="get_level_display", read_only=True)
# Serializer嵌套,不是read_only,一定要自定义create和update,自定义新增和更新的逻辑。
depart = DepartModelSerializer(many=False)
roles = RoleModelSerializer(many=True)
extra = serializers.SerializerMethodField(read_only=True)
email2 = serializers.EmailField(write_only=True)
# 数据校验:username、email、email2、部门、角色信息
class Meta:
model = models.UserInfo
fields = [
"username", "age", "email", "level_text", "depart", "roles", "extra", "email2"
]
extra_kwargs = {
"age": {"read_only": True},
"email": {"validators": [EmailValidator, ]},
}
def get_extra(self, obj):
return 666
def validate_username(self, value):
return value
# 新增加数据时
def create(self, validated_data):
""" 如果有嵌套的Serializer,在进行数据校验时,只有两种选择:
1. 将嵌套的序列化设置成 read_only
2. 自定义create和update方法,自定义新建和更新的逻辑
注意:用户端提交数据的格式。
"""
depart_id = validated_data.pop('depart')['id']
role_id_list = [ele['id'] for ele in validated_data.pop('roles')]
# 新增用户表
validated_data['depart_id'] = depart_id
user_object = models.UserInfo.objects.create(**validated_data)
# 在用户表和角色表的关联表中添加对应关系
user_object.roles.add(*role_id_list)
return user_object
class UserView(APIView):
""" 用户管理 """
def get(self, request):
""" 添加用户 """
queryset = models.UserInfo.objects.all()
ser = UserModelSerializer(instance=queryset, many=True)
return Response({"code": 0, 'data': ser.data})
def post(self, request):
""" 添加用户 """
ser = UserModelSerializer(data=request.data)
if not ser.is_valid():
return Response({'code': 1006, 'data': ser.errors})
ser.validated_data.pop('email2')
instance = ser.save(age=18, password="123", depart_id=1)
# 新增之后的一个对象(内部调用UserModelSerializer进行序列化)
print(instance)
# ser = UserModelSerializer(instance=instance, many=False)
# ser.data
return Response({'code': 0, 'data': ser.data})
数据校验和序列化:
-
可以通过来设置该字段只在序列化或者校验时起作用
-
如果有嵌套的Serializer,在进行数据校验时,只有两种选择:
-
将嵌套的序列化设置成 read_only
-
自定义create和update方法,自定义新建和更新的逻辑据的格式,并且还要对嵌套类的字段设置
read_only
和write_only
:extra_kwargs = { "id": {"read_only": False}, # 数据验证 "title": {"read_only": True} # 序列化 }
-
-
当数据校验完成后,save时会返回新增的对象。(此时data就是序列化后的值)
底层源码实现
序列化的底层源码实现有别于上述其他的组件,序列化器相关类的定义和执行都是在视图中被调用的,所以源码的分析过程可以分为:定义类、序列化、数据校验。
源码1:序列化过程
源码2:数据校验过程
若有错误与不足请指出,关注DPT一起进步吧!!