DRF的Serializer组件(源码分析)

这篇具有很好参考价值的文章主要介绍了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': '创建成功'})

DRF的Serializer组件(源码分析)

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
       }
   ]
}

示例三: 序列化类的嵌套

嵌套主要是面向外键和多对多表的时候

DRF的Serializer组件(源码分析)

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})

返回值:

DRF的Serializer组件(源码分析)

4. 源码分析

底层源码实现:

序列化的底层源码实现有别于上述其他的组件,序列化器相关类的定义和执行都是在视图中被调用的,所以源码的分析过程可以分为:定义类、序列化、数据校验。

源码1:序列化过程

DRF的Serializer组件(源码分析)

DRF的Serializer组件(源码分析)

源码2:数据校验过程

DRF的Serializer组件(源码分析)

DRF的Serializer组件(源码分析)文章来源地址https://www.toymoban.com/news/detail-421804.html

到了这里,关于DRF的Serializer组件(源码分析)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • web应用模式、API接口、接口测试工具postman、如何在浏览器中测试、restful规范、序列化反序列化、基于Django原生编写五个接口、drf介绍和快速使用、drf之APIView源码分析

    目录 一、web应用模式 二、API接口 三、接口测试工具postman postman介绍 postman下载与使用 四、如何在浏览器中测试 五、restful规范(重要) 六、序列化反序列化 七、基于Django原生编写五个接口 八、drf介绍和快速使用 概念 特点(了解一下) 安装 使用drf编写五个接口 九、drf之API

    2024年02月05日
    浏览(59)
  • DRF的filter组件

    如果某个API需要传递一些条件进行搜索,其实就在是URL后面通过GET传参即可,例如: 在drf中filter组件可以支持条件搜索。 返回值: 在drf开发中有一个常用的第三方过滤器:DjangoFilterBackend。 注册app: 视图配置和应用: 视图配置和应用(示例3): lookup_expr 有很多常见选择:

    2023年04月23日
    浏览(32)
  • drf之day04: drf请求与响应,drf能够解析的请求编码,响应编码,drf之视图组件,2个视图基类

    一:drf之请求与响应 1.Request类 1.继承APIView后,请求对象requests每次请求都是一个新的request 2.data: POST, PUT, PATCH请求方式解析后的数据 3.原生django,put提交的数据在request.POST中是娶不到的 4.其他方法用起来和之前是一样的(method, FILES, path) 2.Response类 参数 功能 data=None 把字典,

    2023年04月12日
    浏览(83)
  • drf之频率类源码

    2024年02月07日
    浏览(22)
  • 【Django 05】Django-DRF(ModelViewSet)、路由组件、自定义函数

    ModelViewSet 是 Django REST framework 提供的一个视图集类,它封装了常见的模型操作方法。 模型类提供了默认的增删改查功能。 它继承自 GenericViewSet 、 ListModelMixin 、 RetrieveModelMixin 、 CreateModelMixin 、 UpdateModelMixin 、 DestoryModelMixin 。 知识点 请求 url 特点 GenericViewSet 提供一组通用的

    2024年02月08日
    浏览(43)
  • flink源码分析之功能组件(五)-高可用组件

         本系列是flink源码分析的第二个系列,上一个《flink源码分析之集群与资源》分析集群与资源,本系列分析功能组件,kubeclient,rpc,心跳,高可用,slotpool,rest,metrics,future。      本文解释高可用组件,包括两项服务, 主节点选举 和 主节点变更通知 *     高可用服

    2024年02月01日
    浏览(47)
  • Django的message组件(源码分析)

    第一种: 视图中读取 第二种: 模版中读取 我们根据django的生命周期, 从Middleware入手, process_request: 将SessionStorage对象封装到request的_message(咱们的案例里面也有将用户信息封装到request中, 这样在中间件中添加方便后期调用) process_response: 将message对象反序列化后储存到session/Cookie中

    2024年02月01日
    浏览(32)
  • element-ui 组件库 button 源码分析

    团队要根据新的 UI 规范实现一个组件库, button 组件规范要支持多种主题换肤,字体颜色、背景颜色、边框和禁用使用新的规范,并且一种主题颜色 主要组件 上使用两种主题颜色混合。另外,增加多一种幽灵按钮类型,经过分析,在 element-ui 的 button 组件上改造麻烦,不好维

    2023年04月08日
    浏览(39)
  • 分析 vant4 源码,学会用 vue3 + ts 开发毫秒级渲染的倒计时组件,真是妙啊

    2022年11月23日首发于掘金,现在同步到公众号。 11. 前言 大家好,我是若川。推荐点右上方蓝字若川视野把我的公众号 设为星标 。我倾力持续组织了一年多源码共读,感兴趣的可以加我微信 lxchuan12 参与。另外,想学源码,极力推荐关注我写的专栏《学习源码整体架构系列》

    2024年02月05日
    浏览(101)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包