Django:当用户提交未完成的表单时如何引发异常?

时间:2012-11-21 21:29:28

标签: python django forms error-handling

我有一个相对标准的RegistrationForm,如下所示:

class RegisterForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'username'}), initial='')
    email = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': 'email'}), initial='')
    password = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'password'}), initial='')
    password_repeat = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'retype password'}), initial='')

如何在用户忘记填写一个或多个字段时创建一个返回错误的干净方法? (即“您忘记填写电子邮件字段”)

我在clean()方法中尝试了以下两个选项(我将使用password和password_repeat字段作为示例):

password = self.cleaned_data['password']
password_repeat = self.cleaned_data['password_repeat']
# initial values are set to '' for all fields, see above.
if password == '':
    raise forms.ValidationError("You forgot to type in a password.")
elif password_repeat == '':
        raise forms.ValidationError("You forgot to retype your password.")

第一个选项返回:

/ homepage /

中的KeyError

'密码'


try:
    password = self.cleaned_data['password']
    password_repeat = self.cleaned_data['password_repeat']
except KeyError(password):
    raise forms.ValidationError("You forgot to fill in the password field.")

第二个选项返回:

/ homepage /

中的UnboundLocalError 分配前引用的

本地变量'password'


如果您可以提供允许检查其余字段的解决方案,那么

奖励积分(这样我就可以返回绑定到用户成功提交的数据的表单)。

3 个答案:

答案 0 :(得分:5)

您可以使用可用于所有Field类型的required属性,这些属性会自动执行此类验证。所以你的代码看起来像是:

class RegisterForm(forms.Form):
    username = forms.CharField(
        widget = forms.TextInput(attrs = {'placeholder': 'username'}),
        required = True)
    email = forms.EmailField(
        widget = forms.TextInput(attrs = {'placeholder': 'email'}),
        required = True)
    password = forms.CharField(
        widget = forms.PasswordInput(attrs = {'placeholder': 'password'}),
        required = True)
    password_repeat = forms.CharField(
        widget = forms.PasswordInput(attrs = {'placeholder': 'retype password'}),
        required = True)

注意:我认为您也可以省略initial = ''个参数,如上所示。

我实际上不确定您为什么会收到问题中提到的错误,也许您可​​以发布views.py中的相关代码?可能是因为您需要在实施的任何cleaned_data方法的末尾返回clean

我还想说你使用clean方法并不完全正确。如果您参考form and field validation上的文档的此页面,您会看到要验证单个字段,请使用特定的clean_<fieldname>方法,例如clean_password_repeat。当验证同时涉及多个字段时,使用clean方法是合适的,您可能想要使用的一个示例是检查两个密码字段匹配的输入。

class RegisterForm(forms.Form):
    # field definitions (above)

    def clean(self):
        password = self.cleaned_data['password']
        password_repeat = self.cleaned_data['password_repeat']
        if password != password_repeat:
            raise forms.ValidationError(u"Passwords do not match.")
        return cleaned_data

注意:代码未经过测试。

我希望这有用!

答案 1 :(得分:1)

从django 1.2开始,它可以写validation code on model。我总是在模型方面编写业务规则:

这是你的模特:

from django.db import models
class Issue(models.Model):
    ....

    def clean(self): 
        rules.Issue_clean(self)

#I write business rules into another file ...
def Incidencia_clean( instance ): 
    import datetime as dt

    errors = {}

    #some business rules:     
    if not instance.dia_incidencia: 
        errors.setdefault('b1',[]).append(u'Falten...ranja')

    if not  instance.franja_incidencia: 
        errors.setdefault('b2',[]).append(u'Falten..nja')

    if instance.dia_incidencia < ( dt.date.today() + 
                                   dt.timedelta( days = -7) ): 
        errors.setdefault('b3',[]).append(u'''No es ... setmana)''')

    if instance.getDate() > datetime.now(): 
        errors.setdefault('b4',[]).append(u'''Encara ...itzat.''') 

    if len( errors ) > 0: 
        raise ValidationError(errors) 

在模板中:

{% if form.non_field_errors %}
      {% for error in form.non_field_errors %}
        {{error}}
      {% endfor %}
{% endif %}  

我更喜欢在模型中写一次业务规则,而不是在每种形式中重复规则。

答案 2 :(得分:0)

这是一个片段,它遍历dict中的键,如果其中任何一个映射到空字符串或任何其他类似False的值,则会引发异常。该异常会告诉您dict中的哪个键缺少一个条目。

for key in self.cleaned_data:
    if not self.cleaned_data[key]:
        raise forms.ValidationError("You didn't fill in the {} form".format(key))

如果您只想测试空字符串(而不是False0[]等),请将if not self.cleaned_data[key]:更改为if self.cleaned_data[key] == '':。< / p>