在 Django REST Framework (DRF) 中,序列化器和模型类有明确的职责划分。虽然序列化器在反序列化时负责接收、验证和转换数据,但模型类仍是整个系统的核心,承担更底层的职责。以下是详细解析:
一、序列化器 vs 模型类:职责对比
职责 序列化器 模型类
数据存储 | ❌ 不直接操作数据库 | ✅ 定义数据结构,直接操作数据 |
数据验证 | ✅ 验证请求数据的格式和业务规则 | ✅ 定义数据库层面的约束(如唯一性) |
数据转换 | ✅ 序列化(对象→JSON)和反序列化(JSON→对象) | ❌ 仅存储原始数据 |
业务逻辑 | ⚠️ 处理与请求/响应相关的逻辑(如字段级校验) | ✅ 处理与数据密切相关的核心逻辑(如状态变更) |
数据库关系 | ✅ 描述关联关系的序列化方式 | ✅ 定义外键、多对多等数据库关系 |
生命周期钩子 | ❌ 仅限create()和update() | ✅ 支持save()、delete()前后的信号或pre_save等方法 |
二、为什么需要模型类?
数据持久化
模型类直接与数据库交互,负责数据的存储、查询、更新、删除(CRUD)。序列化器仅生成 Python 字典或模型实例,最终仍需调用模型的save()方法保存到数据库。
数据结构和约束
模型类通过字段(如CharField、ForeignKey)定义数据库表结构,并支持数据库级别的约束(如unique=True、db_index)。
核心业务逻辑
所有与数据直接相关的逻辑(如订单状态变更、用户积分计算)应放在模型类中,确保逻辑的复用性和一致性。
三、业务逻辑应该放在哪里?
1. 适合放在模型类中的逻辑
数据生命周期操作
例如:创建订单后自动发送邮件、删除用户时级联清理关联数据。
class Order(models.Model):
status = models.CharField(max_length=20)
def mark_as_paid(self):
self.status = "paid"
self.save()
self.send_payment_confirmation_email() # 调用发送邮件的逻辑
复杂计算或状态变更
例如:根据用户行为更新统计指标。
class UserProfile(models.Model):
points = models.IntegerField()
def add_points(self, amount):
self.points += amount
self.save()
数据库层面的验证
如通过模型的clean()方法补充校验:
class Article(models.Model):
pub_date = models.DateField()
def clean(self):
if self.pub_date > timezone.now().date():
raise ValidationError("发布日期不能晚于当前日期")
2. 适合放在序列化器中的逻辑
请求数据的校验和转换
例如:验证密码复杂度、动态修改输入数据。
class UserSerializer(serializers.ModelSerializer):
def validate_password(self, value):
if len(value) < 8:
raise serializers.ValidationError("密码至少8位")
return make_password(value) # 对密码进行哈希处理
特定 API 的定制逻辑
例如:在创建对象时附加额外操作(如记录日志)。
class PostSerializer(serializers.ModelSerializer):
def create(self, validated_data):
post = super().create(validated_data)
log_activity(user=post.author, action="create_post") # 记录活动日志
return post
动态字段控制
例如:根据用户权限返回不同字段。
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email', 'is_staff']
def to_representation(self, instance):
data = super().to_representation(instance)
if not self.context['request'].user.is_staff:
del data['is_staff'] # 普通用户隐藏 is_staff 字段
return data
3. 适合放在视图(View)中的逻辑
权限控制
例如:检查用户是否有权访问某个资源。
请求流程协调
例如:根据请求参数组合多个模型操作。
四、如何避免职责混乱?
遵循“Fat Models, Thin Serializers”原则
将核心业务逻辑下沉到模型类,序列化器仅处理与输入输出相关的逻辑。
不要重复校验
数据库约束(如unique=True)和模型校验(clean())是最后防线,序列化器的校验应专注于请求数据的预处理。
慎用序列化器的save()
如果保存对象时需要复杂操作,优先在模型类中定义自定义方法,而不是在序列化器中覆盖create()/update()。
五、示例场景
场景:用户注册
模型类
class User(models.Model):
username = models.CharField(max_length=30, unique=True)
email = models.EmailField(unique=True)
password = models.CharField(max_length=128)
def set_password(self, raw_password):
self.password = make_password(raw_password) # 密码哈希化
序列化器
class UserRegistrationSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
class Meta:
model = User
fields = ['username', 'email', 'password']
def validate_username(self, value):
if 'admin' in value:
raise ValidationError("用户名不能包含 admin")
return value
def create(self, validated_data):
user = User(**validated_data)
user.set_password(validated_data['password']) # 调用模型的密码处理逻辑
user.save()
return user
视图
class UserRegistrationView(APIView):
def post(self, request):
serializer = UserRegistrationSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)
六、总结
模型类:负责数据存储、核心业务逻辑和数据库层面的约束。
序列化器:负责数据校验、格式转换和与 API 交互的临时逻辑。
业务逻辑归属:
模型类:数据生命周期、复杂计算、跨接口复用逻辑。
序列化器:请求数据校验、输入输出定制化。
视图:权限控制、流程协调。
通过合理分层,可以避免代码冗余,提高可维护性和可扩展性。