一. 什么是 Serializer?
Serializer 在 DRF 中负责:
- 序列化:将模型实例/Python 对象 → 转换为 JSON等格式
- 反序列化:将客户端传入的数据 → 转换为 Python 对象 → 再保存到数据库
- 数据验证:检查输入数据是否符合业务规则
from rest_framework import serializers
# 示例模型
class User(models.Model):
username = models.CharField(max_length=100)
email = models.EmailField()
is_active = models.BooleanField(default=True)
# 手动定义 Serializer
class UserSerializer(serializers.Serializer):
username = serializers.CharField(max_length=100)
email = serializers.EmailField()
is_active = serializers.BooleanField()
二. 为什么需要手动定义 Serializer?
- 非模型数据:处理不与数据库直接关联的数据(如聚合结果)
- 定制字段:需要完全控制字段行为时
- 混合数据源:组合多个模型的数据
- 性能优化:仅暴露必要字段
✅ 使用场景对比:
| 场景 |
Serializer |
ModelSerializer |
| 简单模型映射 |
△ |
✅ |
| 复杂字段逻辑 |
✅ |
△ |
| 快速原型开发 |
△ |
✅ |
| 非模型数据 |
✅ |
❌ |
三. 基础用法
3.1 序列化(对象 → 字典)
# 单个对象序列化
user = User.objects.get(id=1)
serializer = UserSerializer(user)
serializer.data # 输出:{'username': 'john', 'email': 'john@example.com', ...}
# 多个对象序列化
users = User.objects.all()
serializer = UserSerializer(users, many=True)
print(serializer.data)
3.2 反序列化(字典 → 对象)
data = {'username': 'alice', 'email': 'alice@example.com'}
serializer = UserSerializer(data=data)
if serializer.is_valid():
validated_data = serializer.validated_data # 获取验证后的数据
else:
errors = serializer.errors # 获取错误信息
四. 字段详解
4.1 字段类型
基础类型字段
| 字段类型 |
描述 |
示例 |
| BooleanField |
布尔值处理 |
is_active = BooleanField(default=True) |
| FloatField |
浮点数处理 |
rating =FloatField(min_value=0.0, max_value=5.0) |
| DecimalField |
高精度十进制数处理(适合金额) |
price =DecimalField(max_digits=10, decimal_places=2) |
| SlugField |
Slug 格式字符串(字母、数字、下划线、连字符) |
slug = SlugField(max_length=50) |
| URLField |
URL 格式验证 |
website = URLField(allow_blank=True) |
| UUIDField |
UUID 格式字符串 |
id = UUIDField(format='hex_verbose') |
| JSONField |
JSON 数据编码/解码 |
metadata =JSONField(binary=False) |
关系型字段
| 字段类型 |
描述 |
示例 |
| StringRelatedField |
显示关联模型的 __str__ 方法返回值 |
author = StringRelatedField() |
| HyperlinkedRelatedField |
生成超链接指向关联资源的 API 端点 |
posts = HyperlinkedRelatedField(view_name='post-detail', many=True) |
| SlugRelatedField |
通过 Slug 字段关联模型 |
category = SlugRelatedField(slug_field='name', queryset=Category.objects.all()) |
| HyperlinkedIdentityField |
生成当前对象的超链接 |
url = HyperlinkedIdentityField(view_name='user-detail') |
| NestedSerializer |
嵌套其他序列化器(非字段,但常用于关系处理) |
comments = CommentSerializer(many=True) |
文件与二进制数据
| 字段类型 |
描述 |
示例 |
| ImageField |
图片上传(继承自 FileField,自动验证图片格式) |
avatar = ImageField(max_length=100, allow_empty_file=False) |
| DictField |
字典类型数据验证 |
config = DictField(child=CharField()) |
| HStoreField |
PostgreSQL HStore 字段支持 |
attributes=HStoreField() |
| BinaryField |
二进制数据(如加密内容) |
encrypted_data = BinaryField() |
日期时间扩展字段
| 字段类型 |
描述 |
示例 |
| DateField |
日期处理(不含时间) |
birthday = DateField(format='%Y-%m-%d', input_formats=['%Y-%m-%d']) |
| TimeField |
时间处理(不含日期) |
start_time = TimeField(format='%H:%M:%S') |
| DurationField |
时长处理(Python timedelta 对象) |
duration = DurationField() |
特殊用途字段
| 字段类型 |
描述 |
示例 |
| HiddenField |
隐藏字段(通常用于自动填充数据,如当前用户) |
user = HiddenField(default=CurrentUserDefault()) |
| ReadOnlyField |
只读字段(仅用于序列化输出) |
created_at = ReadOnlyField() |
| MultipleChoiceField |
多选字段(配合 choices 使用) |
tags = MultipleChoiceField(choices=TAG_CHOICES) |
| ChoiceField |
单选字段 |
status = ChoiceField(choices=STATUS_CHOICES) |
| CustomField |
自定义字段(需继承 Field 类实现) |
见下方示例 |
自定义字段示例
from rest_framework import serializers
class RGBColorField(serializers.Field):
"""
自定义字段:将 "#RRGGBB" 格式字符串转换为 RGB 元组
"""
def to_representation(self, value):
# 从数据库值转换为序列化输出
return {
'r': int(value[1:3], 16),
'g': int(value[3:5], 16),
'b': int(value[5:7], 16)
}
def to_internal_value(self, data):
# 从客户端输入转换为数据库存储格式
hex_color = "#{:02x}{:02x}{:02x}".format(data['r'], data['g'], data['b'])
return hex_color
class ProductSerializer(serializers.Serializer):
color = RGBColorField()
何时使用这些字段?
- 基础扩展字段:处理特定格式数据(如金额用
DecimalField,URL 用 URLField)
- 关系型字段:处理模型关联(如
SlugRelatedField 替代 PrimaryKeyRelatedField 提升可读性)
- 文件与二进制:处理上传文件或二进制内容(如头像用
ImageField)
- 日期时间扩展:精细化控制日期时间格式(如 API 返回 ISO8601 格式时间)
- 特殊用途字段:实现业务定制逻辑(如
HiddenField 自动填充当前用户)
4.2字段参数
DRF Serializer 字段通用参数大全
| 参数名 |
作用描述 |
适用字段类型 |
示例 |
| required |
是否必填(默认 True) |
所有字段 |
email = EmailField(required=False) |
| default |
默认值(支持函数或可调用对象) |
所有字段 |
created = DateTimeField(default=timezone.now) |
| allow_null |
是否允许 None 值(默认 False) |
所有字段 |
middle_name = CharField(allow_null=True) |
| source |
指定模型字段名或方法名 |
所有字段 |
full_name = CharField(source='get_full_name') |
| validators |
自定义验证器列表 |
所有字段 |
age = IntegerField(validators=[validate_age_range]) |
| error_messages |
覆盖默认错误信息 |
所有字段 |
name = CharField(error_messages={'blank': '姓名不能为空'}) |
| style |
控制 HTML 表单渲染样式 |
所有字段 |
password = CharField(style={'input_type': 'password'}) |
| read_only |
字段仅用于序列化输出(默认 False) |
所有字段 |
id = IntegerField(read_only=True) |
| write_only |
字段仅用于反序列化输入(默认 False) |
所有字段 |
password = CharField(write_only=True) |
| label |
字段的友好名称(用于表单和文档) |
所有字段 |
email = EmailField(label='电子邮箱') |
| help_text |
字段的帮助说明(用于表单和文档) |
所有字段 |
content = CharField(help_text='请输入文章内容') |
| initial |
表单中字段的初始值 |
所有字段 |
quantity = IntegerField(initial=1) |
| allow_blank |
允许空字符串(默认 False,仅 CharField 等文本字段有效) |
文本字段 |
bio = CharField(allow_blank=True) |
| trim_whitespace |
自动去除输入值的首尾空格(默认 True,仅 CharField 有效) |
文本字段 |
title = CharField(trim_whitespace=False) |
| min_length |
最小长度限制 |
文本/列表字段 |
username = CharField(min_length=3) |
| max_length |
最大长度限制 |
文本/列表字段 |
password = CharField(max_length=128) |
| min_value |
最小值限制 |
数值字段 |
age = IntegerField(min_value=0) |
| max_value |
最大值限制 |
数值字段 |
score = IntegerField(max_value=100) |
参数说明
read_only 和 write_only
- 使用场景
read_only=True: 字段仅用于输出(如创建时间、ID,用户无法提交修改)
write_only=True: 字段仅用于输入(如密码确认字段,用户无法读取)
- 示例
class UserSerializer(serializers.Serializer):
id = IntegerField(read_only=True) # 用户只能读取,无法提交json修改
password = CharField(write_only=True) # 用户只能写入,程序不会响应给用户password数据
allow_blank 和 trim_whitespace
- 注意:这两个参数仅适用于字符串字段(如
CharField、EmailField)
- 示例
class CommentSerializer(serializers.Serializer):
content = CharField(
allow_blank=False, # 禁止空字符串
trim_whitespace=True # 自动去除首尾空格
)
min_value 和 max_value
- 适用字段:
IntegerField、FloatField、DecimalField
- 示例
class ProductSerializer(serializers.Serializer):
price = DecimalField(
max_digits=10,
decimal_places=2,
min_value=0.01, # 价格必须大于 0
max_value=999999.99
)
error_messages 自定义错误
class UserSerializer(serializers.Serializer):
username = CharField(
min_length=3,
error_messages={
'min_length': '用户名至少需要 {min_length} 个字符', # 支持格式化
'required': '用户名不能为空'
}
)
完整代码示例
from rest_framework import serializers
from django.utils import timezone
class ArticleSerializer(serializers.Serializer):
# 基础参数
title = serializers.CharField(
max_length=100,
label="标题",
help_text="请输入文章标题",
error_messages={'blank': '标题不能为空'}
)
# 时间字段
created_at = serializers.DateTimeField(
read_only=True,
default=timezone.now
)
# 数值字段
views = serializers.IntegerField(
min_value=0,
default=0,
help_text="阅读次数"
)
# 关联字段
author = serializers.PrimaryKeyRelatedField(
queryset=User.objects.all(),
write_only=True # 只允许输入作者ID,输出时不显示
)
# 自定义验证
def validate_title(self, value):
if 'test' in value.lower():
raise serializers.ValidationError("标题不能包含敏感词")
return value
字段参数总结
- 通用参数:不同字段共享的参数(如
required、default)
- 字段特有参数:如
allow_blank(仅字符串字段)、min_value(仅数值字段)
- 最佳实践
- 使用
read_only/write_only 分离输入输出逻辑
- 通过
error_messages 提升错误信息的可读性
- 结合
validators 实现复杂业务规则验证
五. 数据验证
5.1 三层验证机制
- 字段级别验证:单个字段的合法性
- 对象级别验证:多个字段的关系检查
- 自定义验证器:可复用的验证逻辑
5.2 验证示例
class OrderSerializer(serializers.Serializer):
product_id = serializers.IntegerField()
quantity = serializers.IntegerField(min_value=1)
# 字段级验证
def validate_quantity(self, value):
if value > 100:
raise serializers.ValidationError("单次购买不能超过100件")
return value
# 对象级验证
def validate(self, data):
if data['product'].stock < data['quantity']:
raise serializers.ValidationError("库存不足")
return data
# 使用独立验证器
discount_code = serializers.CharField(validators=[validate_discount_code])
六. 保存实例
6.1 必须实现 create() 和 update()
class UserSerializer(serializers.Serializer):
# ...字段定义...
def create(self, validated_data):
return User.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.username = validated_data.get('username', instance.username)
instance.email = validated_data.get('email', instance.email)
instance.save()
return instance
6.2 使用方式
# 创建新对象
serializer = UserSerializer(data=data)
if serializer.is_valid():
user = serializer.save() # 调用 create()
# 更新对象
user = User.objects.get(id=1)
serializer = UserSerializer(user, data=data)
if serializer.is_valid():
updated_user = serializer.save() # 调用 update()
七. 高级技巧
7.1 动态字段
class DynamicUserSerializer(serializers.Serializer):
def __init__(self, *args, **kwargs):
# 根据上下文隐藏敏感字段
fields = kwargs.pop('fields', None)
super().__init__(*args, **kwargs)
if fields is not None:
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
7.2 嵌套序列化
class ProfileSerializer(serializers.Serializer):
address = serializers.CharField()
class UserDetailSerializer(serializers.Serializer):
username = serializers.CharField()
profile = ProfileSerializer() # 嵌套序列化器
八. 常见问题
Q1: serializer.data 返回空字典?
- 检查是否忘记调用
is_valid()
- 确认字段是否被标记为
write_only=True
Q2: 如何处理部分更新?
# 使用 partial=True
serializer = UserSerializer(instance, data={'email': 'new@example.com'}, partial=True)
Q3: 为什么需要 to_representation()?
用于完全自定义输出格式:
def to_representation(self, instance):
data = super().to_representation(instance)
data['status'] = 'active' if instance.is_active else 'inactive'
return data
九. 最佳实践
- 保持简洁:避免在 Serializer 中添加业务逻辑
- 明确职责:验证逻辑放在 Serializer,业务逻辑放在 Model 或 Service 层
- 性能优化:使用
select_related/prefetch_related 避免 N+1 查询
- 版本控制:为不同 API 版本创建不同的 Serializer
- 文档注释:使用
help_text 参数生成 API 文档