admin管理员组文章数量:1516870
从入门到
一. 什么是 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?
- 非模型数据:处理不与数据库直接关联的数据(如聚合结果)
- 定制字段:需要完全控制字段行为时
- 混合数据源:组合多个模型的数据
- 性能优化:仅暴露必要字段
✅ 使用场景对比:
场景 |
|
|
|---|---|---|
简单模型映射 | △ | ✅ |
复杂字段逻辑 | ✅ | △ |
快速原型开发 | △ | ✅ |
非模型数据 | ✅ | ❌ |
三. 基础用法
3.1 序列化(对象 → 字典)
代码语言:python代码运行次数:0运行复制# 单个对象序列化
user = User.objects.get(id=1)
serializer = UserSerializer(user)
serializer.data # 输出:{'username': 'john', 'email': 'john@example', ...}
# 多个对象序列化
users = User.objects.all()
serializer = UserSerializer(users, many=True)
print(serializer.data)3.2 反序列化(字典 → 对象)
代码语言:python代码运行次数:0运行复制data = {'username': 'alice', 'email': 'alice@example'}
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 | 显示关联模型的 | 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 | 图片上传(继承自 | 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 | duration = DurationField() |
特殊用途字段
字段类型 | 描述 | 示例 |
|---|---|---|
HiddenField | 隐藏字段(通常用于自动填充数据,如当前用户) | user = HiddenField(default=CurrentUserDefault()) |
ReadOnlyField | 只读字段(仅用于序列化输出) | created_at = ReadOnlyField() |
MultipleChoiceField | 多选字段(配合 | tags = MultipleChoiceField(choices=TAG_CHOICES) |
ChoiceField | 单选字段 | status = ChoiceField(choices=STATUS_CHOICES) |
CustomField | 自定义字段(需继承 | 见下方示例 |
自定义字段示例
代码语言:python代码运行次数:0运行复制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': '用户名不能为空'
}
)完整代码示例
代码语言:python代码运行次数:0运行复制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 验证示例
代码语言:python代码运行次数:0运行复制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()
代码语言:python代码运行次数:0运行复制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 instance6.2 使用方式
代码语言:python代码运行次数:0运行复制# 创建新对象
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 动态字段
代码语言:python代码运行次数:0运行复制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 嵌套序列化
代码语言:python代码运行次数:0运行复制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: 如何处理部分更新?
代码语言:python代码运行次数:0运行复制# 使用 partial=True
serializer = UserSerializer(instance, data={'email': 'new@example'}, partial=True)Q3: 为什么需要 to_representation()?
用于完全自定义输出格式:
代码语言:python代码运行次数:0运行复制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 文档
本文标签: 从入门到
版权声明:本文标题:从入门到 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.betaflare.com/biancheng/1749323047a2935473.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。


发表评论