Django中SuccessMessageMixin结合CreateView报错:'Quiz'无cleaned_data属性
为什么会触发AttributeError: 'Quiz' object has no attribute 'cleaned_data'?
这个错误的核心原因是你在form_valid方法里的传参逻辑出错了:
你处理完表单后,把保存后的Quiz模型实例(quiz_form)传给了super().form_valid(),但SuccessMessageMixin的form_valid逻辑是依赖表单对象的——它需要从表单的cleaned_data里提取参数,来填充success_message中的%(title)s占位符。而模型实例(比如你的Quiz对象)根本没有cleaned_data这个属性,所以直接触发了报错。
至于UpdateView里能正常工作,大概率是因为你在UpdateView的form_valid里是直接把原表单对象传给父类方法,没有替换成模型实例,所以Mixin能正常获取cleaned_data。
修复步骤
1. 修正form_valid方法的逻辑
你不需要手动调用form.save(commit=False)再传给父类,正确的做法是先给表单的instance关联course,然后直接把原表单传给父类的form_valid,这样父类会自动处理保存,同时SuccessMessageMixin也能正常拿到表单的cleaned_data:
def form_valid(self, form): course_pk = self.kwargs.get(self.pk_url_kwarg) # 直接给表单的待保存实例关联course form.instance.course = get_object_or_404(models.Course, pk=course_pk) # 调用父类方法,传入原表单对象 response = super().form_valid(form) # 这里可以获取保存后的quiz实例 self.saved_quiz = form.instance return response
2. 修正视图的model配置
你的QuizCreateView里model = "course"是错误的!CreateView需要明确知道你要创建的是Quiz模型,所以应该改成:
model = models.Quiz
这个错误虽然不是这次报错的直接原因,但会导致视图的默认逻辑出错,必须修正。
如何获取保存后的Quiz ID?
当表单被成功保存后,form.instance就是已经持久化到数据库的Quiz对象,它的pk属性就是你要的ID。你可以在form_valid里把它存在视图实例的属性中,之后在get_success_url或者其他方法中使用:
比如:
def form_valid(self, form): course_pk = self.kwargs.get(self.pk_url_kwarg) form.instance.course = get_object_or_404(models.Course, pk=course_pk) response = super().form_valid(form) # 保存Quiz ID到视图实例 self.quiz_id = form.instance.pk return response # 示例:如果要跳转到Quiz详情页,可以在get_success_url里使用 def get_success_url(self): course_pk = self.kwargs["course_pk"] # 假设你有一个quiz_detail的URL配置 return reverse_lazy('courses:quiz_detail', kwargs={'course_pk': course_pk, 'quiz_pk': self.quiz_id})
如果只是需要在成功消息里用到ID,也可以修改success_message为"%(title)s was created successfully (ID: %(pk)s)"——SuccessMessageMixin会自动把模型实例的属性也作为上下文变量(不过cleaned_data里的字段优先级更高,所以如果你的表单里有pk字段的话会优先用表单的,否则用模型实例的)。
内容的提问来源于stack exchange,提问作者Jeremy Chen

