为什么检查Django中的两个密码是否匹配如此复杂?

时间:2010-07-12 06:02:23

标签: django design-patterns

我做错了什么,或者严重每次我想检查两个字段是否相同时,开发人员希望我写的是什么?

def clean(self):
    data = self.cleaned_data
    if "password1" in data and "password2" in data:
        if data["password1"] != data["password2"]:
            self._errors["password2"] = self.error_class(['Passwords do not match.'])
            del data['password2']    
    return data

为什么我必须验证用户名是否唯一?

def clean_username(self):
    data = self.cleaned_data['username']
    if User.objects.filter(username=data).exists():
        raise ValidationError('Username already taken.')
    return data

这是一个ModelForm。它应该已经知道有一个独特的约束条件吗?

4 个答案:

答案 0 :(得分:28)

这就是我要做的事情:

这是您需要定义的唯一干净方法,以确保2个密码正确并且用户名有效。

使用clean_fieldname方法,这样您就不需要做更多工作来验证用户名。

def clean_password2(self):
    password1 = self.cleaned_data.get('password1')
    password2 = self.cleaned_data.get('password2')

    if not password2:
        raise forms.ValidationError("You must confirm your password")
    if password1 != password2:
        raise forms.ValidationError("Your passwords do not match")
    return password2

您绝对正确,需要验证用户名是唯一的,因为ModelForm知道它必须是唯一的。

您的代码存在的问题是您要覆盖clean()方法,这意味着ModelForm不会执行其真正的'干净()。

要获得默认验证,请致电super(MyForm, self).clean()或更好,但根本不要覆盖clean并仅指定clean_password2

答案 1 :(得分:4)

首先,您是否严重抱怨四行样板代码?如果它真的困扰你,请创建一个包含该干净逻辑的PasswordForm类,并根据需要将其子类化为您自己的表单。

其次,您必须手动验证唯一约束。如你所说,ModelForm为你做到了。

在评论后修改

这种“奇怪的语法”是因为检查两个密码字段匹配的是不同的流而不是正常的方案。首先,您要检查主clean方法,而不是特定于字段的clean_myfield。如果它是后者,你只是引发异常,Django确实删除了字段数据。

所以不,这不是每个表单上的7行 - 请参阅我关于子类化的说明 - 并且当然不是7行乘以多个字段,因为你不想这样做对于任何其他类型的领域。

答案 2 :(得分:4)

http://k0001.wordpress.com/2007/11/15/dual-password-field-with-django/


修改:找出管理表单处理问题的方式:http://code.djangoproject.com/svn/django/trunk/django/contrib/auth/forms.py

class AdminPasswordChangeForm(forms.Form):
    """
    A form used to change the password of a user in the admin interface.
    """
    password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
    password2 = forms.CharField(label=_("Password (again)"), widget=forms.PasswordInput)

    def __init__(self, user, *args, **kwargs):
        self.user = user
        super(AdminPasswordChangeForm, self).__init__(*args, **kwargs)

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')
        if password1 and password2:
            if password1 != password2:
                raise forms.ValidationError(_("The two password fields didn't match."))
        return password2

    def save(self, commit=True):
        """
        Saves the new password.
        """
        self.user.set_password(self.cleaned_data["password1"])
        if commit:
            self.user.save()
        return self.user

答案 3 :(得分:1)

您可能希望为第一个else:添加if部分。目前该函数返回data而不设置任何错误,即使其中一个密码不存在 - 是否是预期的行为?

else:
    self._errors["password"] = self.error_class(['One or both of the passwords not found'])

if "password1" in data and "password2" in data:这可以确保两个密码都存在。如果没有这一行,如果其中任何一个不存在,您将在下一行中看到data[password1]data[password2]的错误。

接下来的三行比较密码并设置相应的错误信息 - 这是必需的,不是吗?

正如他们所说,让事情尽可能简单,不再是。