验证设计:表单还是视图?

Validation design: form or view?

我制作了一个 "edit profile" 表格,您可以在其中完成一件非常经典的事情:更改密码。

因此我有 3 个字段:旧密码、新密码和重新输入新密码。

问题出在设计上。 我首先检查输入的所有内容是否正常 ,格式为 clean method:

def clean(self):
    old = self.cleaned_data.get('old_password')
    new1 = self.cleaned_data.get('new_password1')
    new2 = self.cleaned_data.get('new_password2')
    if old:
        if not new1:
            raise ValidationError(_(u'New password missing'))
        if not new2:
            raise ValidationError(_(u'New password missing'))
        if new1 != new2:
            raise ValidationError(_(u"The new password "
                                    u"is not the same twice"))
    return super(ProfileForm, self).clean()

在我的表单中,除非我破解,否则我无法访问当前登录的用户。 我的问题是关于设计的:是否更好地破解表单代码,然后在 form is_valid() 中更改密码,还是在 view form_valid() 方法中更好?

首先,Django 自带了一个 view and form 来更改密码],你应该尽可能使用它们。

如果你真的需要修改自己的视图和表单,我觉得在views form_valid()方法中修改密码是可以的。

您可以将设置新密码的代码移动到表单上的一个方法中,然后在form_valid方法中调用该方法。这种方法的缺点是您必须重写表单的 __init__ 方法和视图的 get_form_kwargs 方法才能将用户传递给表单,这使它变得更加复杂。好处是你把功能封装在视图里了。

不要覆盖表单的 is_valid() 方法。此方法的目的是检查表单是否有效。您很少需要覆盖它。

Django 实际上有一个 built-in 表单用于更改用户密码,您可以参考。请参阅 SetPasswordFormPasswordChangeForm 上的 https://github.com/django/django/blob/master/django/contrib/auth/forms.py

不要更改is_valid()方法中的密码,它仅用于验证。您可以重写表单的 __init__ 来获取用户,并使用 save 方法来更改密码。

class MyForm(forms.Form):

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

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

密码更改操作应该在单独的方法中在表单中完成。以下是您需要的视图代码示例:

class MyView(TemplateView):

    def post(self, request, *args, **kwargs):
        form = MyForm(user=request.user, data=request.POST)
        if form.is_valid():
            form.save() # password updated
            return redirect(<somehwere>)

        # the password change has failed form validation
        return self.render_to_response({})

为了回答您的问题,最好在表单中更改密码,而不是在视图中更改密码。在表单中执行数据操作(例如 ModelForm.save())是 Django 中相当常见的模式,并且大多数 Django 自己的代码也会更改表单中的模型数据。

这将更改模型数据的逻辑与视图分开,并使单元测试和推理变得更加容易(例如,您不需要依赖视图来测试更改密码操作)。