在Django中使用CreateView时,表单clean方法无法获取request对象的问题
问题:表单clean方法中无法获取request对象,报错
'NoneType' object has no attribute 'user' 我尝试在表单的clean方法中获取request对象,但实际并未成功传递,提交表单时出现错误:'NoneType' object has no attribute 'user'。
我的表单代码
class MyModelForm(ModelForm): class Meta: model = MyModel fields=['question',] def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) super(MyModelForm, self).__init__(*args, **kwargs) def clean(self, *args, **kwargs): data = self.cleaned_data['question'] user = self.request.user if user.author.number_of_questions < 1: raise ValidationError("You don't have any questions left") return data
我的CreateView代码
class MyModelCreate(generic.CreateView): model = MyModel fields=['question',] def form_valid(self, form): # Code return super(MyModelCreate, self).form_valid(form) def get_success_url(self, **kwargs): # obj = form.instance or self.object return reverse_lazy('articles:thank-you') def get_form_kwargs(self): kw = super(MyModelCreate, self).get_form_kwargs() kw['request'] = self.request # the trick! return kw def get_context_data(self, **kwargs): #Code return context
我原本认为CreateView中的get_form_kwargs方法会将self.request传递给表单的request参数,从而在MyModelForm的clean方法中访问,但运行代码时仍出现上述错误,不清楚request对象未传递的原因。
问题原因及解决方案
核心问题
你的MyModelCreate视图中使用了fields参数,这会让Django自动生成一个默认的ModelForm,而不是你自定义的MyModelForm。所以你在get_form_kwargs中传递的request根本没传到你写的表单里,导致self.request始终是None,访问self.request.user就会触发报错。
修复步骤
指定自定义表单类
在MyModelCreate中替换fields=['question',]为form_class = MyModelForm,这样Django才会使用你定义的表单:class MyModelCreate(generic.CreateView): model = MyModel form_class = MyModelForm # 替换原来的fields参数 # 其他方法保持不变修正clean方法的返回值
表单的clean方法应该返回完整的self.cleaned_data,而不是只返回单个字段的值,否则会丢失验证后的其他数据:def clean(self): data = self.cleaned_data.get('question') user = self.request.user if user.author.number_of_questions < 1: raise ValidationError("你没有剩余的提问次数了") return self.cleaned_data # 返回完整的cleaned_data增加request存在性判断(可选但推荐)
为了避免未登录或request未正常传递时的报错,可以在clean方法开头增加判断:def clean(self): if not self.request or not self.request.user.is_authenticated: raise ValidationError("请先登录") data = self.cleaned_data.get('question') user = self.request.user if user.author.number_of_questions < 1: raise ValidationError("你没有剩余的提问次数了") return self.cleaned_data
内容的提问来源于stack exchange,提问作者Joshua Hovden
相关产品推荐
相关产品推荐

