实用指南:Django序列化器

什么是序列化器(Serializer)?

序列化器是 DRF 中用于:

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

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

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

✅ 可扩展点:

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

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

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

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

前端提交 JSON 数据
      ↓
初始化序列化器(传入 data + context)
      ↓
调用 .is_valid()
      ↓
字段级校验:
    ├─ 字段类型转换(CharField, IntegerField 等)
    ├─ validate_(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

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

用法示例:

# 序列化(对象 → 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

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

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(只读字段)

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

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 映射字段

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

real_name = serializers.CharField(source='profile.real_name')

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

3. 自定义字段类型

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

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

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

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

三、校验逻辑详解

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

用于校验单个字段的值:

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

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

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

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

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

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

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

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

然后在字段中使用:

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_()
5. 对象级校验:validate(self, attrs)

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

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

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

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

用途场景

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

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

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

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

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

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

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

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 可以自动处理嵌套写入:

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
数据校验自动校验字段类型、格式、必填项
字段控制控制哪些字段可读、可写、只读、隐藏等
嵌套结构支持嵌套模型、反查字段、自定义字段
企业级扩展支持权限控制、字段映射、动态字段、字段级别权限等

posted @ 2025-12-13 11:14  yangykaifa  阅读(23)  评论(0)    收藏  举报