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

时间:2022-12-01 10:51:24

I've got a relatively standard RegistrationForm that looks like this:

我有一个相对标准的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='')

How could I create a clean method that returns an error when a user forgets to fill in one or more fields? (ie. "You forgot to fill in the email field")

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

I've tried the following two options in my clean() method (I'll use the password and password_repeat fields as examples):

我在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.")

The first option returns:

第一个选项返回:

KeyError at /homepage/

/ homepage /的KeyError /

'password'


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.")

The second option returns:

第二个选项返回:

UnboundLocalError at /homepage/

/ homepage /的UnboundLocalError

local variable 'password' referenced before assignment

在赋值之前引用的局部变量'password'


Bonus points if you can provide a solution that allows for the remaining fields to be checked as well (so that I can return an form bound to the data the user successfully submitted).

如果您可以提供允许检查其余字段的解决方案,那么奖励点(这样我就可以返回绑定到用户成功提交的数据的表单)。

3 个解决方案

#1


5  

You can use the required property available for all Field types, which automatically does this type of validation. So your code would look like:

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

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)

Note: I think you can leave out those initial = '' parameters as well, as shown above.

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

I'm actually not sure why you're getting the errors you mentioned in your question, perhaps you could post the relevant code from your views.py? It could be because you need to return cleaned_data at the end of any clean method you implement.

我实际上不确定你为什么会收到你在问题中提到的错误,或许你可以发布你的views.py中的相关代码?这可能是因为您需要在实现的任何干净方法结束时返回cleaning_data。

I would also just say that your use of the clean method is not quite right. If you refer to this page of the documentation on form and field validation you see that to validate a single field you use the specific clean_<fieldname> method e.g. clean_password_repeat. Using the clean method is appropriate when validation involves multiple field simultaneously, one example of this you may like to use is checking the inputs for the two password fields match.

我也只是说你使用干净的方法是不对的。如果您参考表单和字段验证文档的此页面,您会看到要验证单个字段,请使用特定的clean_ 方法,例如: 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

Note: Code is not tested.

注意:代码未经过测试。

I hope this was helpful!

我希望这可以帮到你!

#2


1  

Since django 1.2 it is able to write validation code on model. I allways write business rules in model side:

从django 1.2开始,它能够在模型上编写验证代码。我总是在模型方面编写业务规则:

This is your 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) 

In template:

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

I prefer to write business rule one time in model than repeat rules into each form.

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

#3


0  

Here is a snippet that steps through the keys in a dict and raises an exception if any of them are mapped to the empty string or any other False-like value. The exception tells you which key in the dict was missing an entry.

这是一个片段,它遍历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))

If you exclusively want to test for empty strings (and not False, 0, [], etc), change if not self.cleaned_data[key]: to if self.cleaned_data[key] == '':.

如果你只想测试空字符串(而不是False,0,[]等),如果不是self.cleaned_data [key]:改变为self.cleaned_data [key] =='':.

#1


5  

You can use the required property available for all Field types, which automatically does this type of validation. So your code would look like:

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

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)

Note: I think you can leave out those initial = '' parameters as well, as shown above.

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

I'm actually not sure why you're getting the errors you mentioned in your question, perhaps you could post the relevant code from your views.py? It could be because you need to return cleaned_data at the end of any clean method you implement.

我实际上不确定你为什么会收到你在问题中提到的错误,或许你可以发布你的views.py中的相关代码?这可能是因为您需要在实现的任何干净方法结束时返回cleaning_data。

I would also just say that your use of the clean method is not quite right. If you refer to this page of the documentation on form and field validation you see that to validate a single field you use the specific clean_<fieldname> method e.g. clean_password_repeat. Using the clean method is appropriate when validation involves multiple field simultaneously, one example of this you may like to use is checking the inputs for the two password fields match.

我也只是说你使用干净的方法是不对的。如果您参考表单和字段验证文档的此页面,您会看到要验证单个字段,请使用特定的clean_ 方法,例如: 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

Note: Code is not tested.

注意:代码未经过测试。

I hope this was helpful!

我希望这可以帮到你!

#2


1  

Since django 1.2 it is able to write validation code on model. I allways write business rules in model side:

从django 1.2开始,它能够在模型上编写验证代码。我总是在模型方面编写业务规则:

This is your 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) 

In template:

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

I prefer to write business rule one time in model than repeat rules into each form.

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

#3


0  

Here is a snippet that steps through the keys in a dict and raises an exception if any of them are mapped to the empty string or any other False-like value. The exception tells you which key in the dict was missing an entry.

这是一个片段,它遍历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))

If you exclusively want to test for empty strings (and not False, 0, [], etc), change if not self.cleaned_data[key]: to if self.cleaned_data[key] == '':.

如果你只想测试空字符串(而不是False,0,[]等),如果不是self.cleaned_data [key]:改变为self.cleaned_data [key] =='':.