DRF的Serializer组件(源码分析)
DRF的Serializer组件(源码分析)
1. 数据校验
drf中为我们提供了Serializer,他主要有两大功能:
- 对请求数据校验(底层调用Django的Form和ModelForm)
- 对数据库查询到的对象进行序列化
示例一: 基于Serializer
# models.py
class UserInfo(models.Model):
username = models.CharField(verbose_name='用户名', max_length=32)
age = models.CharField(verbose_name='年龄', max_length=32)
level_choice = ((1, 'VIP'), (2, 'SVIP'), (3, 'PARTNER'))
level = models.CharField(verbose_name='级别', choices=level_choice, max_length=32)
email = models.CharField(verbose_name='邮箱', max_length=32)
# views.py 基于Serializer
class UserSerializers(serializers.Serializer):
username = serializers.CharField(label='用户名', max_length=32)
age = serializers.CharField(label='年龄', max_length=32)
level = serializers.ChoiceField(label='级别', choices=models.UserInfo.level_choice)
email = serializers.CharField(label='用户名', min_length=6, max_length=32, validators=[EmailValidator, ])
email1 = serializers.CharField(label='用户名', min_length=6, max_length=32)
email2 = serializers.CharField(label='用户名', min_length=6, max_length=32)
def validate_email2(self, value):
""" 钩子函数, 用于验证某个字段 """
if re.match('^\w+@\w+\.\w+$', value):
return value
raise exceptions.ValidationError('邮箱格式错误')
class UserView(APIView):
""" 用户管理 """
def post(self, request):
""" 添加用户 """
ser = UserSerializers(data=request.data) # 将请求体数据传入, 这个request.data可以解析各种数据
if not ser.is_valid():
return Response({'code': 1006, 'data': ser.errors})
print(ser.validated_data)
# 将数据保存到数据库
return Response({'code': 0, 'data': 'xxxx'})
示例二: 基于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):
username = models.CharField(verbose_name='用户名', max_length=32)
age = models.CharField(verbose_name='年龄', max_length=32)
level_choice = ((1, 'VIP'), (2, 'SVIP'), (3, 'PARTNER'))
level = models.CharField(verbose_name='级别', choices=level_choice, max_length=32)
email = models.CharField(verbose_name='邮箱', max_length=32)
# 创建外键
depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE)
# 多对多
roles = models.ManyToManyField(verbose_name="角色", to="Role")
# views.py
# 基于ModelSerializer
class UserModelSerializer(serializers.ModelSerializer):
email1 = serializers.CharField(label='邮箱1', validators=[EmailValidator, ])
class Meta:
model = models.UserInfo
fields = ['username', 'age', 'email', 'email1', 'roles'] # 需要传入的数据, 多对多
extra_kwargs = {
'username': {'min_length': 4, 'max_length': 32},
'age': {'max_length': 3}
}
def valicate_email(self, value):
....
return value
class UserView(APIView):
""" 用户管理 """
def post(self, request):
""" 添加用户 """
ser = UserModelSerializer(data=request.data) # 将请求体数据传入, 这个request.data可以解析各种数据
if not ser.is_valid():
return Response({'code': 1006, 'data': ser.errors})
print(ser.validated_data)
# 将数据保存到数据库
ser.validated_data.pop('email1') # 删除不需要存入数据库的数据
ser.save(level=1, depart_id=1) # 加入初始化数据
return Response({'code': 0, 'data': '创建成功'})
2. 序列化
示例一: 序列化基本字段
class UserModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = ['username', 'age', 'level', 'email', 'depart', 'roles'] # 序列化基本字段
class UserView(APIView):
""" 用户管理 """
def get(self, request):
""" 序列化数据 """
queryset = models.UserInfo.objects.all()
ser = UserModelSerializer(instance=queryset, many=True)
print(ser.data)
return Response({'code': 0, 'data': ser.data})
返回值:
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept {
"code": 0,
"data": [
{
"username": "ifeng",
"age": "11",
"level": 1,
"email": "ifeng190410@gmail.com",
"depart": 1,
"roles": []
},
{
"username": "Mcoco",
"age": "11",
"level": 1,
"email": "ifeng190410@gmail.com",
"depart": 1,
"roles": [
1,
2
]
}
]
}
示例二: 自定义字段
from django.forms.models import model_to_dict
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.views import APIView
from api import models
class UserModelSerializer(serializers.ModelSerializer):
# 自定义字段
level_text = serializers.CharField(source="get_level_display")
depart = serializers.CharField(source='depart.title')
roles = serializers.SerializerMethodField()
extra = serializers.SerializerMethodField()
class Meta:
model = models.UserInfo
fields = ['username', 'age', 'level_text', 'email', 'depart', 'roles', 'extra']
def get_roles(self, obj):
data_list = obj.roles.all()
return [model_to_dict(item, ['id', 'title']) for item in data_list]
def get_extra(self, obj):
return 666
class UserView(APIView):
""" 用户管理 """
def get(self, request):
""" 序列化数据 """
queryset = models.UserInfo.objects.all()
ser = UserModelSerializer(instance=queryset, many=True)
print(ser.data)
return Response({'code': 0, 'data': ser.data})
返回值:
{
"code": 0,
"data": [
{
"username": "ifeng",
"age": "11",
"level_text": "SVIP",
"email": "ifeng190410@gmail.com",
"depart": "后端",
"roles": [],
"extra": 666
},
{
"username": "Mcoco",
"age": "11",
"level_text": "VIP",
"email": "ifeng190410@gmail.com",
"depart": "销售",
"roles": [
{
"id": 1,
"title": "CEO"
},
{
"id": 2,
"title": "CFO"
}
],
"extra": 666
}
]
}
示例三: 序列化类的嵌套
嵌套主要是面向外键和多对多表的时候
3. 数据校验&序列化
注意点:
我们在做多对多数据校验的时候, 后面如果需要新增数据, 则需要重写create方法, 如果需要更新数据, 则需要重写update方法
# mdoels.py
from django.db import models
# Create your models here.
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):
username = models.CharField(verbose_name='用户名', max_length=32)
age = models.CharField(verbose_name='年龄', max_length=32)
level_choice = ((1, 'VIP'), (2, 'SVIP'), (3, 'PARTNER'))
level = models.SmallIntegerField(verbose_name='级别', choices=level_choice) # 类型为Int
email = models.CharField(verbose_name='邮箱', max_length=32)
# 创建外键
depart = models.ForeignKey(verbose_name="部门", to="Department", on_delete=models.CASCADE)
# 多对多
roles = models.ManyToManyField(verbose_name="角色", to="Role")
# views.py
# 数据校验&序列化
class DepartModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Department
fields = ['id', "title"]
extra_kwargs = {
"id": {"read_only": False}, # 数据验证, 需传入id, 为后续的create做准备
"title": {"read_only": True} # 序列化
}
class RoleModelSerializer(serializers.ModelSerializer):
class Meta:
model = models.Role
fields = ['id', "title"]
extra_kwargs = {
"id": {"read_only": False}, # 数据校验, 需传入id, 为后续的create做准备
"title": {"read_only": True} # 序列化
}
class UserModelSerializer(serializers.ModelSerializer):
level_text = serializers.CharField(source="get_level_display", read_only=True) # read_only -> 只序列化, 但是不数据校验
# 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) # write_only -> 只数据校验不序列化
# 数据校验:username、email、email2、部门、角色信息
class Meta:
model = models.UserInfo
# username, age, email是即read_only也write_only
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
# 新增加数据时, 因为无法解决m2m的储存问题. 所以需要重写create方法
def create(self, validated_data):
"""
如果有嵌套的Serializer,在进行数据校验时,只有两种选择:
1. 将嵌套的序列化设置成 read_only
2. 自定义create和update方法,自定义新建和更新的逻辑
注意:用户端提交数据的格式。
"""
"""
validated_data:
OrderedDict([('username', 'xiaoergu'), ('email', 'xiaoergu@gmail.com'), ('depart', OrderedDict([('id', 2)])), ('roles', [OrderedDict([('id', 1)]), OrderedDict([('id', 2)])]), ('email2', 'budianlong@gmail.com')])
"""
depart_id = validated_data.pop('depart')['id'] # 拿到depart的id
role_id_list = [ele['id'] for ele in validated_data.pop('roles')] # 拿到roles的所有id
# 新增用户表
validated_data['depart_id'] = depart_id
user_object = models.UserInfo.objects.create(**validated_data)
# 在用户表和角色表的关联表中添加对应关系, django-orm知识
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})
print(ser.validated_data)
ser.validated_data.pop('email2')
instance = ser.save(age=18, level=3)
# 新增之后的一个对象(内部调用UserModelSerializer进行序列化)
print(instance)
# ser = UserModelSerializer(instance=instance, many=False)
# ser.data
return Response({'code': 0, 'data': ser.data})
返回值:
4. 源码分析
底层源码实现:
序列化的底层源码实现有别于上述其他的组件,序列化器相关类的定义和执行都是在视图中被调用的,所以源码的分析过程可以分为:定义类、序列化、数据校验。
源码1
:序列化过程
源码2
:数据校验过程
DRF的Serializer组件(源码分析)的更多相关文章
- Django框架之drf:8、断点调试,权限、认证、频率组件源码分析,基于APIView编写分页,异常处理
Django框架之drf 一.断点调式使用 指,在我们编写代码的时候,程序运行出现报错是无可避免的,当程序 出现报错时,我们需要找到出现报错的代码进行修改,如果时简短的代码很容易就可以找到报错位置 ...
- Django-restframework 源码之认证组件源码分析
Django-restframework 源码之认证组件源码分析 一 前言 之前在 Django-restframework 的流程分析博客中,把最重要的关于认证.权限和频率的方法找到了.该方法是 A ...
- element-ui 组件源码分析整理笔记目录
element-ui button组件 radio组件源码分析整理笔记(一) element-ui switch组件源码分析整理笔记(二) element-ui inputNumber.Card .B ...
- ceph-csi组件源码分析(1)-组件介绍与部署yaml分析
更多ceph-csi其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 ceph-csi组件源码分析(1)-组件介绍与部署yaml分析 基于tag v3.0.0 ht ...
- 开源MyBatisGenerator组件源码分析
开源MyBatisGenerator组件源码分析 看源码前,先了解Generator能做什么? MyBatisGenerator是用来生成mybatis的Mapper接口和xml文件的工具,提供多种启 ...
- DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render
DRF框架 全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...
- drf 简介以及部分源码分析
目录 复习 drf框架 全称:django-rest framework 知识点 接口 restful接口规范 基于restful规范的原生Django接口 主路由:url.py api组件的子路由: ...
- 探索drf执行流程之APIView源码分析
Django REST framework 简介 现在新一代web应用都开始采用前后端分离的方式来进行,淘汰了以前的服务器端渲染的方式.而实现前后端分离是通过Django REST framework ...
- drf 视图使用及源码分析
前言 drf视图的源码非常的绕,但是实现的功能却非常的神奇. 它能够帮你快速的解决ORM增删改查的重复代码,非常的方便好用. 下面是它源码中的一句话: class ViewSetMixin: &quo ...
- drf快速使用 CBV源码分析 drf之APIView分析 drf之Request对象分析
目录 序列化和反序列化 drf介绍和安装 使用原生django写接口 django DRF安装 drf快速使用 模型 序列化类 视图 路由 datagrip 使用postman测试接口 CBV源码分析 ...
随机推荐
- Pytorch Cross Entropy
Entropy Uncetainly measure of surprise higher entropy = less info \[Entropy = -\sum_i P(i)\log P(i) ...
- 2020/513-笔记:怎么知道Oracle数据库一个中文汉字占几个字节
1. 执行语句: select userenv('language') from dual; 如果显示如下: SIMPLIFIED CHINESE_CH ...
- 变量调用分析——这个ball到底是那个ball?
public class Ball implements Rollable{ public static void main(String[] args) { Ball ball = new Ball ...
- python 把mysql数据导入到execl中
import pymysql import pandas as pd db = pymysql.connect( host='127.0.0.1', user='root', passwd='1234 ...
- Java基础学习——复利计算
面对一个问题的时候,首先应该确定问题中存在多少参数,对每个参数进行定义.并知晓所写代码目标.思路清晰,
- 用猿大师的VLC播放插件在高版本Chrome播放RTSP视频流,并抓图、录像、回放、倍速等
因为项目上需要把海康威视摄像头集成到WEB网页中播放,于是开始了对WEB播放摄像头方案的各种折腾. 2015年之前还可以用VLC原生播放器在Chrome.Firefox等浏览器中直接播放,延迟比较低, ...
- python-GUI-pyqt5之文件加密解密工具
pyqt5的文件加密解密程序,用到base64,rsa和aes进行混合解密,代码比较杂乱,可自行整理,仅供学习参考之用,如需转载,请联系博主或附上博客链接,下面直接干货. 程序截图如下: # -*- ...
- nvm的下载安装
nvm下载地址:https://github.com/coreybutler/nvm-windows/releases 下载包,双击安装,选取路径, 注意:如果按默认的,安装在c盘的话,那之后的切换版 ...
- Python内置函数:index
index用于返回指定值在序列的第一个位置 序列.index(值,开始索引,结束索引) 开始索引默认为0,可不传 结束索引默认为序列长度,可不传 >>> str = 'abc' &g ...
- windows微信如何双开
生活中存在同时使用两个微信的情况,一个工作一个生活,这时希望同时在电脑上登录两个账号.如何做到呢?步骤如下: 右键单击"微信"图标,选择属性,目标框内的路径就是微信安装路径,复制目 ...