Django REST如何处理序列化器中的非模型自定义字段?
Django序列化器自定义字段创建实例报错的解决方法
问题背景
定义了TimeReport模型和对应的创建序列化器,希望通过自定义字段task_custom_id查找关联的Task,但创建模型实例时触发错误:TimeReport() got an unexpected keyword argument 'task_custom_id'。
模型代码
class TimeReport(models.Model): minutes_spent = models.PositiveIntegerField() task = models.ForeignKey(Task, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) reported_for = models.DateField() note = models.TextField(null=True, blank=True) status = models.CharField(max_length=50, choices=State.choices, default=State.new) user = models.ForeignKey(User, on_delete=models.PROTECT)
序列化器代码
class TimeReportCreateSerializer(serializers.ModelSerializer): class Meta: model = TimeReport fields = ( 'id', 'minutes_spent', 'reported_for', 'note', 'status', 'task_custom_id', ) task_custom_id = serializers.CharField() def create(self, validated_data): user = User.objects.get(auth_user_id = self.context['user_id']) task = Task.objects.filter(custom_id = validated_data['task_custom_id']).filter(user = user.id).first() report = TimeReport(**validated_data) report.user = user report.task = task report.save() return report
报错信息
TypeError at /api/report/ TimeReport() got an unexpected keyword argument 'task_custom_id'
核心原因
validated_data中包含了模型没有的task_custom_id字段,直接用**validated_data传递给TimeReport构造器时,模型类不识别这个参数,因此抛出错误。
解决方法
方法1:从validated_data中移除自定义字段(最直接)
在创建模型实例前,把task_custom_id从validated_data中取出并删除,确保剩下的参数都是模型需要的:
def create(self, validated_data): # 取出自定义字段值并从validated_data中移除 task_custom_id = validated_data.pop('task_custom_id') user = User.objects.get(auth_user_id=self.context['user_id']) # 简化查询语句,直接传入user对象而非id task = Task.objects.filter(custom_id=task_custom_id, user=user).first() # 现在validated_data仅包含模型字段,可安全创建实例 report = TimeReport(**validated_data) report.user = user report.task = task report.save() return report
方法2:标记自定义字段为仅写入(更规范)
给task_custom_id添加write_only=True属性,明确该字段只用于接收输入,不参与序列化输出,同时配合方法1的pop操作:
# 修改序列化器字段定义 task_custom_id = serializers.CharField(write_only=True) # create方法同方法1 def create(self, validated_data): task_custom_id = validated_data.pop('task_custom_id') user = User.objects.get(auth_user_id=self.context['user_id']) task = Task.objects.filter(custom_id=task_custom_id, user=user).first() report = TimeReport(**validated_data) report.user = user report.task = task report.save() return report
额外优化建议
- 增加任务不存在的验证逻辑,避免空值赋值:
def create(self, validated_data): task_custom_id = validated_data.pop('task_custom_id') user = User.objects.get(auth_user_id=self.context['user_id']) task = Task.objects.filter(custom_id=task_custom_id, user=user).first() if not task: raise serializers.ValidationError({"task_custom_id": "当前用户下不存在该自定义ID的任务"}) report = TimeReport(**validated_data) report.user = user report.task = task report.save() return report
内容的提问来源于stack exchange,提问作者Thomas
相关产品推荐
相关产品推荐

