深入理解 Django REST Framework 的 Serializer(上)

一、什么是 Serializer?------ 概念与作用

1.1、核心定义

Serializer 负责将复杂数据类型(如 Django 模型实例)转换为 Python 原生数据类型(如 dict),以便渲染为 JSON/XML;同时也能将解析后的数据反向验证并转换回复杂类型。

1.2、两大核心功能

  • 序列化(Serialization):对象 → 字典(用于响应)
  • 反序列化(Deserialization):字典 → 对象(用于请求)

而在序列化与反序列化中一定绕不开下表的方法,也是我们理解序列化器的前提

这两个方法均在 rest_framework\serializers.py下的 Serializer 类中,后续我会一一讲解

|----------|----------------------------------|-------------------------|
| 方向 | 方法 | 用途 |
| 输入(反序列化) | to_internal_value() → validate() | 把前端数据转成干净 Python 对象 |
| 输出(序列化) | to_representation() | 把 Python 对象转成 JSON 安全字典 |
[序列化器的两个任务]

二、如何定义 Serializer?

2.1 以serializers.Serializer 为例

1、定义类继承serializers.Serializer

python 复制代码
from rest_framework import serializers


class MobileLoginModelSerializer(serializers.Serializer):

2、根据业务以及逻辑定义字段

在这里我是做短信登录,所以需要用到 mobile code(短信验证码)字段,而手机号长度通常为11位,短信验证码长度在4-6位,设置只写。

++注:如果你不明白为什么要写这些,或者为什么要写这些,可以先跳过。等学完 反序列化 回头再看这里++

python 复制代码
from rest_framework import serializers


class MobileLoginModelSerializer(serializers.Serializer):
    mobile = serializers.CharField(
        max_length=11, write_only=True)
    
    code = serializers.CharField(
        min_length=4, max_length=6, write_only=True)

也许你还知道ModelSerializer 这个序列化器,你可能会疑惑?为什么 ModelSerializer 中不需要写那么多参数,因为这个序列化器会继承其在Model中声明过的字段及其参数。而普通 Serializer 的字段不会自动获得任何约束,除非你写出来!


3、定义字段验证方法及整体验证方法

其中如果是对字段的验证方法 遵循以下原则

  1. 方法名以 validate_xxx命名 xxx为该字段名称 比如要验证手机号 在上述我的字段命名为mobile,所以就是 validate_mobile
  2. 必须返回一个值,如果你只是检验没有修改 直接返回参数中的value即可,如果你对这个参数进行了修改就返回修改后的值

如果是对整体进行验证 遵循以下原则

  1. 必须返回参数的attrs,可以对这个attrs进行添加新数据,但是必须返回!
python 复制代码
from rest_framework import serializers


class MobileLoginModelSerializer(serializers.Serializer):
    
    ...省略上述代码

    def validate_mobile(self, value):
        if not User.objects.get(mobile=value):
            raise serializers.ValidationError("手机号不存在",code='mobile')
        return value

    def validate(self, attrs):
        mobile = attrs.get('mobile')
        code = attrs.get('code')

        redis = get_redis_connection('sms_code')
        key = f'sms_{mobile}_login'

        # 1.获取Redis短信验证码判断是否存在
        stored_code = redis.get(key)
        if stored_code is None:
            raise serializers.ValidationError("验证码已过期",code='code')
        # 2.判断 code:attrs 与 code:redis
        if stored_code.decode() != code:
            raise serializers.ValidationError("验证码错误,请重新确认",code='code')

        redis.delete(key)
        attrs['user'] = User.objects.get(mobile=mobile)
        return attrs

三、如何使用定义好的 Serializer?

3.1 以APIView视图为例

1、实例化序列化器类

我们需要传入的参数分别是

request.data 用于反序列化数据校验

context 在这里先按下不表,后面会出一个专门的文章讲解这个参数的作用。新手只需记住必须传这个参数

python 复制代码
from rest_framework.views import APIView
from .serializers import MobileLoginModelSerializer

class MobileLoginAPIView(APIView):
    def post(self, request):
        # 1. 序列化器验证数据
        serializer = MobileLoginModelSerializer(
                        data=request.data, context={'request':request}
                    )

2、调用is_valid()方法

调用这个方法 序列化器就会校验本次传入的数据是否合法(根据我们设置的校验规则)

python 复制代码
from rest_framework.views import APIView
from .serializers import MobileLoginModelSerializer

class MobileLoginAPIView(APIView):
    def post(self, request):
        # 1. 序列化器验证数据
        serializer = MobileLoginModelSerializer(
                        data=request.data,
                        context={'request':request})

        if not serializer.is_valid():
            return Response(data=serializer.errors,status=status.HTTP_400_BAD_REQUEST)

四、总结

一个简单但完整的序列化器使用过程就是这样的,可以总结成以下的步骤

  1. 定义字段,设置字段参数
  2. 定义字段校验方法,整体校验方法 (如有需求)
  3. 实例化序列化器,调用is_valid方法

在下篇文章中,我会继续深入研究 is_valid方法做了什么 如何完成反序列化及数据校验

相关推荐
weixin_568996061 分钟前
Python开发Flask项目如何部署到云服务器_使用Fabric自动化发布脚本
jvm·数据库·python
m0_596406373 分钟前
Python中正确声明、重新赋值并安全使用None变量的完整指南
jvm·数据库·python
Word码3 分钟前
QQ音乐自动化测试实战指南
python·功能测试·测试工具·pycharm·集成测试
m0_716430075 分钟前
实现 Flex 容器内子元素自适应高度并启用自动滚动
jvm·数据库·python
weixin_381288185 分钟前
c++怎么在写入文本文件时自动将所有的制表符统一转换为四格空格【实战】
jvm·数据库·python
聆风吟º6 分钟前
【Python编程日志】Python入门基础(二):行 | 缩进 | print输出
开发语言·python·print··缩进
m0_743623927 分钟前
MySQL导入大SQL文件报错怎么办_拆分文件与优化系统参数
jvm·数据库·python
weixin_424999368 分钟前
组件懒加载如何处理 JS 报错后的重试加载?保障应用高可用性实战
jvm·数据库·python
baidu_340998829 分钟前
SQL中如何通过视图实现行级加密_CASE WHEN语句的妙用
jvm·数据库·python
qq_372154239 分钟前
mysql如何限制单用户最大连接数_修改max_user_connections
jvm·数据库·python