Django序列化器

什么是序列化器(Serializer)?

序列化器是 DRF 中用于:

功能 描述
序列化 将模型对象转换为 JSON,返回给前端
反序列化 将前端传来的 JSON 数据转换为模型对象
校验 自动校验字段类型、必填项、格式等
字段控制 控制哪些字段可读、可写、只读、隐藏等

一、序列化流程图解(对象 → JSON)

复制代码
模型对象 / QuerySet
      ↓
初始化序列化器(传入 instance)
      ↓
调用 .data → 触发 to_representation()
      ↓
遍历字段:
    ├─ 普通字段 → 字段.to_representation(obj.field)
    ├─ SerializerMethodField → get_<field>(obj)
    ├─ 嵌套序列化器 → 子序列化器.to_representation()
    └─ source 映射字段 → 取值后序列化
      ↓
返回 JSON 数据(OrderedDict)

✅ 可扩展点:

  • 重写 to_representation(self, instance):自定义输出结构

  • 使用 SerializerMethodField:动态字段、格式化展示

  • 嵌套序列化器:展示关联对象详情(如角色、权限)

二、反序列化流程图解(JSON → 模型)

复制代码
前端提交 JSON 数据
      ↓
初始化序列化器(传入 data + context)
      ↓
调用 .is_valid()
      ↓
字段级校验:
    ├─ 字段类型转换(CharField, IntegerField 等)
    ├─ validate_<field>(value)
    └─ validators(如 UniqueValidator、自定义校验器)
      ↓
对象级校验:
    └─ validate(self, attrs)
      ↓
调用 .save()
    ├─ create(validated_data)(用于 POST)
    └─ update(instance, validated_data)(用于 PUT/PATCH)
      ↓
写入数据库,返回模型对象

✅ 可扩展点:

  • validate_<field>(self, value):字段级校验

  • validate(self, attrs):对象级联合校验

  • create() / update():处理嵌套写入、逻辑外键、多对多中间表等

  • context['request']:用于获取当前用户、租户、IP 等上下文信息

一、基础使用:ModelSerializer

python 复制代码
from rest_framework import serializers
from .models import User

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'status']

用法示例:

python 复制代码
# 序列化(对象 → JSON)
user = User.objects.get(id=1)
serializer = UserSerializer(user)
print(serializer.data)

# 反序列化(JSON → 对象)
data = {'username': 'tom', 'email': 'tom@example.com', 'status': 1}
serializer = UserSerializer(data=data)
if serializer.is_valid():
    serializer.save()

二、自定义字段

字段属性控制

属性 描述
read_only=True 只读字段,前端不能提交
write_only=True 仅写字段,序列化时不输出
required=True 必填字段
default=value 默认值,可为函数如 timezone.now
allow_null=True 允许为 null

添加只读字段、隐藏字段、默认值

python 复制代码
class UserSerializer(serializers.ModelSerializer):
    status = serializers.IntegerField(default=1)
    creator_id = serializers.IntegerField(write_only=True)
    create_time = serializers.DateTimeField(read_only=True)

    class Meta:
        model = User
        fields = '__all__'

自定义字段的几种方式

1. SerializerMethodField(只读字段)

用于展示模型中不存在的字段,或需要计算/拼接的字段:

python 复制代码
class UserSerializer(serializers.ModelSerializer):
    display_name = serializers.SerializerMethodField()

    def get_display_name(self, obj):
        return obj.real_name or obj.username

    class Meta:
        model = User
        fields = ['id', 'username', 'real_name', 'display_name']

适合格式化输出、拼接字段、反查字段(如角色列表、部门名称)

2. source 映射字段

用于将序列化字段映射到模型中的其他字段或属性:

python 复制代码
real_name = serializers.CharField(source='profile.real_name')

适合跨模型字段、属性方法、嵌套字段简化

3. 自定义字段类型

你可以直接使用 CharField, IntegerField, BooleanField 等,并设置属性:

python 复制代码
status = serializers.IntegerField(default=1, required=False, help_text='状态(0禁用,1启用)')

可控制默认值、是否必填、提示信息等

能力 技术点 企业价值
自定义字段 SerializerMethodField, source 提升输出语义、格式化展示

三、校验逻辑详解

1. 字段级校验:validate_<field_name>

用于校验单个字段的值:

python 复制代码
def validate_username(self, value):
    if 'admin' in value:
        raise serializers.ValidationError("用户名不能包含 'admin'")
    return value

适合格式限制、敏感词过滤、唯一性校验等

2. 对象级校验:validate(self, attrs)

用于多个字段之间的联合校验:

python 复制代码
def validate(self, attrs):
    if attrs['status'] == 0 and not attrs.get('email'):
        raise serializers.ValidationError("禁用用户必须填写邮箱")
    return attrs

适合状态联动、条件判断、业务规则校验

3. 自定义校验器类(推荐企业项目使用)

python 复制代码
from rest_framework.validators import ValidationError

def validate_phone(value):
    if not value.startswith('1'):
        raise ValidationError("手机号必须以 1 开头")

然后在字段中使用:

python 复制代码
phone = serializers.CharField(validators=[validate_phone])

可复用、集中管理、便于测试

4. 字段行为控制:extra_kwargs(隐性校验器)

extra_kwargsModelSerializer.Meta 中的配置项,用于控制字段的行为,从而影响校验流程:

复制代码
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['username', 'email', 'password']
        extra_kwargs = {
            'password': {'write_only': True},
            'email': {
                'required': False,
                'allow_null': True,
                'error_messages': {
                    'required': '邮箱不能为空',
                    'invalid': '邮箱格式不正确'
                }
            }
        }
配置项 说明
required 是否为必填字段(默认 True)
allow_null 是否允许为 null
default 设置默认值
read_only 设置为只读字段,前端无法提交
write_only 设置为只写字段,响应中不返回
error_messages 自定义错误提示,支持国际化

适合快速控制字段行为,避免显式声明字段,提升序列化器的简洁性和可维护性。

能力对照表(含 extra_kwargs

能力 技术点 企业价值
字段级校验 validate_<field>() 控制字段合法性
对象级校验 validate(self, attrs) 实现业务规则
校验器复用 自定义函数或类 提升可维护性、集中管理
字段行为控制 extra_kwargs 控制字段是否必填、只读、默认值、提示

多种校验方式共同使用时的执行顺序

当你调用 .is_valid() 时,DRF 会按以下顺序执行校验逻辑:

复制代码
1. extra_kwargs → 预处理字段行为(如 required, default, allow_null)
2. 字段类型转换(CharField, IntegerField 等)
3. 字段 validators(如 UniqueValidator、自定义校验器函数)
4. 字段级校验:validate_<field_name>()
5. 对象级校验:validate(self, attrs)

✅ 注意:如果前面某一层校验失败,后续校验将不会执行。

四、嵌套序列化与多对多处理

一、嵌套序列化器的用途和类型

嵌套序列化器是指在一个序列化器中嵌入另一个序列化器,用于处理关联模型字段。

用途场景

类型 示例字段 描述
一对多 User → Department 用户所属部门
多对多 User → Roles 用户拥有多个角色
反查字段 Role → Users 角色下的用户列表
逻辑外键反查 Permission → Menu 权限关联菜单

二、只读嵌套序列化器(展示用)

适用于展示关联对象详情,但不支持写入:

python 复制代码
class RoleSerializer(serializers.ModelSerializer):
    class Meta:
        model = Role
        fields = ['id', 'name']

class UserSerializer(serializers.ModelSerializer):
    roles = serializers.SerializerMethodField()

    def get_roles(self, obj):
        role_ids = UserRole.objects.filter(user_id=obj.id).values_list('role_id', flat=True)
        roles = Role.objects.filter(id__in=role_ids)
        return RoleSerializer(roles, many=True).data

    class Meta:
        model = User
        fields = ['id', 'username', 'roles']

适合逻辑外键结构,手动反查并嵌套序列化器输出

三、可写嵌套序列化器(创建/更新用)

适用于前端提交嵌套结构时写入关联关系:

python 复制代码
class RoleInputSerializer(serializers.ModelSerializer):
    class Meta:
        model = Role
        fields = ['id']

class UserCreateSerializer(serializers.ModelSerializer):
    roles = RoleInputSerializer(many=True)

    class Meta:
        model = User
        fields = ['username', 'email', 'roles']

    def create(self, validated_data):
        roles_data = validated_data.pop('roles')
        user = User.objects.create(**validated_data)
        for role in roles_data:
            UserRole.objects.create(user_id=user.id, role_id=role['id'])
        return user

适合多对多逻辑外键结构,手动处理中间表写入

四、自动多对多处理(仅适用于 ManyToManyField

如果你使用 Django 原生的 ManyToManyField,DRF 可以自动处理嵌套写入:

python 复制代码
class User(models.Model):
    roles = models.ManyToManyField(Role, through='UserRole')

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'roles']

⚠️ 你当前使用的是逻辑外键结构(UserRole 中间表),所以需要手动处理嵌套写入

五、企业项目中的最佳实践

场景 推荐做法
✅ 展示嵌套字段 使用 SerializerMethodField + 子序列化器封装
✅ 写入嵌套字段 使用输入序列化器 + 重写 create() / update()
✅ 多对多逻辑外键 手动维护中间表(如 UserRole, RolePermission
✅ 字段权限控制 使用 read_only, write_only, required 控制嵌套字段行为
✅ 分离输入输出序列化器 UserCreateSerializer, UserDetailSerializer 分开定义,职责清晰

总结:序列化器的核心价值

能力 说明
数据转换 模型对象 ↔ JSON
数据校验 自动校验字段类型、格式、必填项
字段控制 控制哪些字段可读、可写、只读、隐藏等
嵌套结构 支持嵌套模型、反查字段、自定义字段
企业级扩展 支持权限控制、字段映射、动态字段、字段级别权限等
相关推荐
懷淰メ1 小时前
python3GUI--短视频社交软件 By:Django+PyQt5(前后端分离项目)
后端·python·django·音视频·pyqt·抖音·前后端
woshihonghonga1 小时前
【动手学深度学习】
开发语言·python
码界筑梦坊2 小时前
240-基于Python的医疗疾病数据可视化分析系统
开发语言·python·信息可视化·数据分析·毕业设计·echarts
有意义2 小时前
从零搭建:json-server+Bootstrap+OpenAI 全栈 AI 小项目
前端·后端·llm
MoRanzhi12032 小时前
Python 实现:从数学模型到完整控制台版《2048》游戏
数据结构·python·算法·游戏·数学建模·矩阵·2048
2401_841495643 小时前
【数据结构】基于BF算法的树种病毒检测
java·数据结构·c++·python·算法·字符串·模式匹配
汤姆yu3 小时前
基于springboot的民间救援队救助系统
java·spring boot·后端·救援队