serializer 中的read_only 和 write_only介绍

在 Django REST Framework (DRF) 中,read_only 和 write_only 是 Serializer 字段的重要参数,用于控制字段在序列化(输出)和反序列化(输入)时的行为。以下是详细介绍:

1. read_only=True

#作用:
- 序列化时包含该字段(API 返回数据中会显示)
- 反序列化时忽略该字段(用户无法通过请求修改该字段)
- 通常用于自动生成或计算的字段(如 ID、创建时间、计算值等)

#示例:
class UserSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)  # 用户无法修改ID
    created_at = serializers.DateTimeField(read_only=True)  # 自动生成的创建时间
    
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'created_at']
#效果:
请求数据(反序列化):
{
  "username": "test",
  "email": "test@example.com",
  "id": 123,  // 该字段会被忽略
  "created_at": "2025-06-25T10:00:00Z"  // 该字段会被忽略
}
响应数据(序列化):
{
  "id": 1,
  "username": "test",
  "email": "test@example.com",
  "created_at": "2025-06-25T10:00:00Z"
}

2. write_only=True

#作用:
序列化时忽略该字段(API 返回数据中不显示)
反序列化时包含该字段(用户可以通过请求传递该字段)
通常用于敏感信息(如密码、令牌等)或只需写入不需要返回的字段

#示例:
class UserSerializer(serializers.ModelSerializer):
    password = serializers.CharField(write_only=True)  # 密码不应返回给客户端
    
    class Meta:
        model = User
        fields = ['username', 'email', 'password']
    
    def create(self, validated_data):
        # 手动处理密码哈希
        password = validated_data.pop('password')
        user = User.objects.create(**validated_data)
        user.set_password(password)  # 哈希密码
        user.save()
        return user
#效果:
请求数据(反序列化):
{
  "username": "test",
  "email": "test@example.com",
  "password": "securepassword"  // 该字段会被处理
}
响应数据(序列化):
{
  "username": "test",
  "email": "test@example.com"
  // 密码字段不会返回
}

3. 同时使用 read_only 和 write_only

#示例:
假设需要一个字段在创建时由用户提供(write_only),但创建后只能读取(read_only)。可以通过两个字段实现:
class OrderSerializer(serializers.ModelSerializer):
    # 创建时用户提供优惠券代码
    coupon_code = serializers.CharField(write_only=True, required=False)
    
    # 创建后返回优惠券折扣金额
    discount_amount = serializers.DecimalField(
        max_digits=10, 
        decimal_places=2, 
        read_only=True
    )
    
    class Meta:
        model = Order
        fields = ['coupon_code', 'discount_amount', 'total_price']
    
    def create(self, validated_data):
        coupon_code = validated_data.pop('coupon_code', None)
        # 计算折扣逻辑...
        discount = calculate_discount(coupon_code)
        
        order = Order.objects.create(
            discount_amount=discount,
            **validated_data
        )
        return order

4. 在 extra_kwargs 中设置

#在 Meta 类的 extra_kwargs 中设置更简洁:
class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ['id', 'username', 'email', 'password', 'created_at']
        extra_kwargs = {
            'id': {'read_only': True},
            'password': {'write_only': True, 'min_length': 8},
            'created_at': {'read_only': True}
        }

5. 常见应用场景

#read_only 的场景
自动生成的字段:id、created_at、updated_at
计算字段:total_price = price * quantity
关联字段:如 user.profile.avatar_url
#write_only 的场景
密码、API 密钥等敏感信息
一次性使用的字段:如验证码、临时令牌
创建 / 更新时需要但无需返回的字段:如 old_password(修改密码时)

6. 注意事项

#验证逻辑:
read_only 字段不会参与反序列化验证
write_only 字段不会参与序列化输出
#默认值:
如果设置 read_only=True,则无需指定 default 值,因为该字段不会被写入
#与 required 的关系:
read_only=True 隐含 required=False
write_only=True 仍可设置 required=True(如果该字段在创建 / 更新时必须提供)

通过合理使用 read_only 和 write_only,可以精确控制 API 的输入输出字段,提高安全性和用户体验。

posted @ 2025-06-25 16:22  幸福的好喜欢  阅读(1)  评论(0)    收藏  举报