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