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组件(源码分析)的更多相关文章

  1. Django框架之drf:8、断点调试,权限、认证、频率组件源码分析,基于APIView编写分页,异常处理

    Django框架之drf 一.断点调式使用 ​ 指,在我们编写代码的时候,程序运行出现报错是无可避免的,当程序 出现报错时,我们需要找到出现报错的代码进行修改,如果时简短的代码很容易就可以找到报错位置 ...

  2. Django-restframework 源码之认证组件源码分析

    Django-restframework 源码之认证组件源码分析 一 前言 之前在 Django-restframework 的流程分析博客中,把最重要的关于认证.权限和频率的方法找到了.该方法是 A ...

  3. element-ui 组件源码分析整理笔记目录

    element-ui button组件 radio组件源码分析整理笔记(一) element-ui switch组件源码分析整理笔记(二) element-ui inputNumber.Card .B ...

  4. ceph-csi组件源码分析(1)-组件介绍与部署yaml分析

    更多ceph-csi其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 ceph-csi组件源码分析(1)-组件介绍与部署yaml分析 基于tag v3.0.0 ht ...

  5. 开源MyBatisGenerator组件源码分析

    开源MyBatisGenerator组件源码分析 看源码前,先了解Generator能做什么? MyBatisGenerator是用来生成mybatis的Mapper接口和xml文件的工具,提供多种启 ...

  6. DRF框架(一)——restful接口规范、基于规范下使用原生django接口查询和增加、原生Django CBV请求生命周期源码分析、drf请求生命周期源码分析、请求模块request、渲染模块render

    DRF框架    全称:django-rest framework 知识点 1.接口:什么是接口.restful接口规范 2.CBV生命周期源码 - 基于restful规范下的CBV接口 3.请求组件 ...

  7. drf 简介以及部分源码分析

    目录 复习 drf框架 全称:django-rest framework 知识点 接口 restful接口规范 基于restful规范的原生Django接口 主路由:url.py api组件的子路由: ...

  8. 探索drf执行流程之APIView源码分析

    Django REST framework 简介 现在新一代web应用都开始采用前后端分离的方式来进行,淘汰了以前的服务器端渲染的方式.而实现前后端分离是通过Django REST framework ...

  9. drf 视图使用及源码分析

    前言 drf视图的源码非常的绕,但是实现的功能却非常的神奇. 它能够帮你快速的解决ORM增删改查的重复代码,非常的方便好用. 下面是它源码中的一句话: class ViewSetMixin: &quo ...

  10. drf快速使用 CBV源码分析 drf之APIView分析 drf之Request对象分析

    目录 序列化和反序列化 drf介绍和安装 使用原生django写接口 django DRF安装 drf快速使用 模型 序列化类 视图 路由 datagrip 使用postman测试接口 CBV源码分析 ...

随机推荐

  1. Pytorch Cross Entropy

    Entropy Uncetainly measure of surprise higher entropy = less info \[Entropy = -\sum_i P(i)\log P(i) ...

  2. 2020/513-笔记:怎么知道Oracle数据库一个中文汉字占几个字节

    1. 执行语句:             select userenv('language') from dual; 如果显示如下:             SIMPLIFIED CHINESE_CH ...

  3. 变量调用分析——这个ball到底是那个ball?

    public class Ball implements Rollable{ public static void main(String[] args) { Ball ball = new Ball ...

  4. python 把mysql数据导入到execl中

    import pymysql import pandas as pd db = pymysql.connect( host='127.0.0.1', user='root', passwd='1234 ...

  5. Java基础学习——复利计算

    面对一个问题的时候,首先应该确定问题中存在多少参数,对每个参数进行定义.并知晓所写代码目标.思路清晰,

  6. 用猿大师的VLC播放插件在高版本Chrome播放RTSP视频流,并抓图、录像、回放、倍速等

    因为项目上需要把海康威视摄像头集成到WEB网页中播放,于是开始了对WEB播放摄像头方案的各种折腾. 2015年之前还可以用VLC原生播放器在Chrome.Firefox等浏览器中直接播放,延迟比较低, ...

  7. python-GUI-pyqt5之文件加密解密工具

    pyqt5的文件加密解密程序,用到base64,rsa和aes进行混合解密,代码比较杂乱,可自行整理,仅供学习参考之用,如需转载,请联系博主或附上博客链接,下面直接干货. 程序截图如下: # -*- ...

  8. nvm的下载安装

    nvm下载地址:https://github.com/coreybutler/nvm-windows/releases 下载包,双击安装,选取路径, 注意:如果按默认的,安装在c盘的话,那之后的切换版 ...

  9. Python内置函数:index

    index用于返回指定值在序列的第一个位置 序列.index(值,开始索引,结束索引) 开始索引默认为0,可不传 结束索引默认为序列长度,可不传 >>> str = 'abc' &g ...

  10. windows微信如何双开

    生活中存在同时使用两个微信的情况,一个工作一个生活,这时希望同时在电脑上登录两个账号.如何做到呢?步骤如下: 右键单击"微信"图标,选择属性,目标框内的路径就是微信安装路径,复制目 ...