前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >从入门到_精通_Django REST Framework-(二)

从入门到_精通_Django REST Framework-(二)

原创
作者头像
rxg456
发布2025-02-25 23:05:52
发布2025-02-25 23:05:52
9500
代码可运行
举报
运行总次数:0
代码可运行

一. 什么是 Serializer?

Serializer 在 DRF 中负责:

  • 序列化:将模型实例/Python 对象 → 转换为 JSON等格式
  • 反序列化:将客户端传入的数据 → 转换为 Python 对象 → 再保存到数据库
  • 数据验证:检查输入数据是否符合业务规则
代码语言:python
代码运行次数:0
复制
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 序列化(对象 → 字典)

代码语言:python
代码运行次数:0
复制
# 单个对象序列化
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 反序列化(字典 → 对象)

代码语言:python
代码运行次数:0
复制
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 类实现)

见下方示例


自定义字段示例
代码语言: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: 字段仅用于输入(如密码确认字段,用户无法读取)
  • 示例
代码语言:python
代码运行次数:0
复制
class UserSerializer(serializers.Serializer):
    id = IntegerField(read_only=True)          # 用户只能读取,无法提交json修改
    password = CharField(write_only=True)      # 用户只能写入,程序不会响应给用户password数据
allow_blank 和 trim_whitespace
  • 注意:这两个参数仅适用于字符串字段(如 CharFieldEmailField
  • 示例
代码语言:python
代码运行次数:0
复制
class CommentSerializer(serializers.Serializer):
    content = CharField(
        allow_blank=False,     # 禁止空字符串
        trim_whitespace=True   # 自动去除首尾空格
    )
min_value 和 max_value
  • 适用字段IntegerFieldFloatFieldDecimalField
  • 示例
代码语言:python
代码运行次数:0
复制
class ProductSerializer(serializers.Serializer):
    price = DecimalField(
        max_digits=10,
        decimal_places=2,
        min_value=0.01,        # 价格必须大于 0
        max_value=999999.99
    )
error_messages 自定义错误
  • 覆盖默认错误码
代码语言:python
代码运行次数:0
复制
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

字段参数总结
  • 通用参数:不同字段共享的参数(如 requireddefault
  • 字段特有参数:如 allow_blank(仅字符串字段)、min_value(仅数值字段)
  • 最佳实践
  • 使用 read_only/write_only 分离输入输出逻辑
  • 通过 error_messages 提升错误信息的可读性
  • 结合 validators 实现复杂业务规则验证

五. 数据验证

5.1 三层验证机制

  1. 字段级别验证:单个字段的合法性
  2. 对象级别验证:多个字段的关系检查
  3. 自定义验证器:可复用的验证逻辑

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 instance

6.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.com'}, 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

九. 最佳实践

  1. 保持简洁:避免在 Serializer 中添加业务逻辑
  2. 明确职责:验证逻辑放在 Serializer,业务逻辑放在 Model 或 Service 层
  3. 性能优化:使用 select_related/prefetch_related 避免 N+1 查询
  4. 版本控制:为不同 API 版本创建不同的 Serializer
  5. 文档注释:使用 help_text 参数生成 API 文档

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. 什么是 Serializer?
  • 二. 为什么需要手动定义 Serializer?
  • 三. 基础用法
    • 3.1 序列化(对象 → 字典)
    • 3.2 反序列化(字典 → 对象)
  • 四. 字段详解
    • 4.1 字段类型
      • 基础类型字段
      • 关系型字段
      • 文件与二进制数据
      • 日期时间扩展字段
      • 特殊用途字段
      • 自定义字段示例
      • 何时使用这些字段?
    • 4.2字段参数
      • DRF Serializer 字段通用参数大全
      • 参数说明
      • read_only 和 write_only
      • allow_blank 和 trim_whitespace
      • min_value 和 max_value
      • error_messages 自定义错误
      • 完整代码示例
      • 字段参数总结
  • 五. 数据验证
    • 5.1 三层验证机制
    • 5.2 验证示例
  • 六. 保存实例
    • 6.1 必须实现 create() 和 update()
    • 6.2 使用方式
  • 七. 高级技巧
    • 7.1 动态字段
    • 7.2 嵌套序列化
  • 八. 常见问题
    • Q1: serializer.data 返回空字典?
    • Q2: 如何处理部分更新?
    • Q3: 为什么需要 to_representation()?
  • 九. 最佳实践
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档