【问题标题】:django form is_valid always fails (extending django-registration form)django form is_valid 总是失败(扩展django-registration form)
【发布时间】:2013-01-17 19:08:09
【问题描述】:

我正在尝试扩展 Django 注册以包含我自己的注册表单。原则上这是相当简单的。我只需要编写自己的表单 (CustomRegistrationForm),它是原始表单 (RegistrationForm) 的子表单。然后我可以使用 django 注册的 user_registered 信号来处理我的特定输入。

这就是我所做的:

urls.py:

from django.conf.urls import patterns, include, url
from registration.views import register
from forms import CustomRegistrationForm
from django.contrib import admin
import regbackend
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^register/$', register, {'backend': 'registration.backends.default.DefaultBackend', 'form_class': CustomRegistrationForm, 'template_name': 'custom_profile/registration_form.html'}, 
                        name='registration_register'),
)

regbackend.py:

from django import forms
from models import UserProfile
from forms import CustomRegistrationForm

def user_created(sender, user, request, **kwargs):
    form = CustomRegistrationForm(data=request.POST, files=request.FILES)
    if form.is_valid(): # HERE: always fails
        user_profile = UserProfile()
        user_profile.user = user
        user_profile.matriculation_number = form.cleaned_data['matriculation_number']
        user_profile.save()

from registration.signals import user_registered
user_registered.connect(user_created)

forms.py:

from models import UserProfile
from django import forms
from registration.forms import RegistrationForm
from django.utils.translation import ugettext_lazy as _

attrs_dict = {'class': 'required'}

class CustomRegistrationForm(RegistrationForm):
    matriculation_number = forms.CharField(widget=forms.TextInput(attrs=attrs_dict),
                                           label=_("Matriculation number"),
                                           max_length=12,
                                           error_messages={'invalid': _("This value has to be unique and may contain only numbers.")},
                                           initial=108)

    def clean_matriculation_number(self):
        print "Validating matriculation number."
        data = self.cleaned_data['matriculation_number']
        if len(data) != 12:
            raise forms.ValidationError(_("Matriculation number consists of exactly 12 digits."))
        return data

所以问题出在is_valid() 函数上,因为它总是返回False。即使没有错误!那么有什么问题呢?我花了几个小时在这个上,我不知道了:(

非常感谢任何帮助!

【问题讨论】:

  • 为什么表单需要files=request.FILES
  • is_valid 只会在出现任何错误时返回 False。您未显示的字段可能存在错误。或者根本不显示错误。使用django-debug-toolbar 检查表单错误(或自己进行深度检查)。
  • @ Abid:我添加了 files=request.FILES 以避免未绑定的表单或其他东西。起初我只使用了 line form = CustomRegistrationForm(request.POST) 并且它不起作用。 @bouke:我正在使用工具栏,并明确检查了错误。没有了。有趣的是,如果我跳过 is_valid() 函数并使用 form.data[...] 而不是cleaned_data,eerythin 就可以工作。所以验证肯定有问题:/

标签: django forms signals registration


【解决方案1】:

form.is_valid() 失败的原因可能是表单的“clean_username”函数检查传递给它的用户名是否已经存在。由于该信号是在创建 User 对象并添加到数据库之后发送的,因此表单每次都无法通过此测试。我的猜测是,如果您在is_valid() 返回False 之后登录form.cleaned_data,您将获得除用户名之外的所有字段的列表。

如果 form clean_ 函数进行任何更改,form.data 可能不包含更改的字段值(我在 form.data 上找不到太多文档)。

为了避免这可能导致的潜在问题,我为我的自定义注册表单制作了两个类:

# I use this one for validating in my create_user_profile function
class MyRegistrationFormInternal(forms.Form):
    # Just an example with only one field that holds a name
    name = forms.CharField(initial="Your name", max_length=100)    
    def clean_name(self):
        # (Optional) Change the name in some way, but do not check to see if it already exists
        return self.cleaned_data['name'] + ' foo '
# This one is actually displayed
class MyRegistrationForm (MyRegistrationFormInternal):
    # Here is where we check if the user already exists
    def clean_name(self):
        modified_name = super(MyRegistrationForm, self).clean_name()
        # Check if a user with this name already exists
        duplicate = (User.objects.filter(name=modified_name)
        if duplicate.exists():
            raise forms.ValidationError("A user with that name already exists.")  
        else:
            return modified_name

然后,您可以通过 MyRegistrationFormInternal 运行您的 POST 数据,而不是使用 form.data(在某些方面可能仍然“不干净”),并且 is_valid() 不应总是返回 false。

我意识到这不是最干净的解决方案,但它避免了使用(可能是原始的)form.data。

【讨论】:

    【解决方案2】:

    好吧,我想我解决了(或多或少)。

    我仍然不确定,为什么表单没有验证。但正如我所说,我正在扩展 django-registration 和已经调用表单的 is_valid() 的“注册”视图,所以我可以假设当我进一步处理发布的数据时表单是有效的。然后视图调用后端

    backend.register(request, **form.cleaned_data)
    

    请求和清理后的数据(只是用户名、电子邮件和密码)。所以我不能用它来注册,因为我的附加信息丢失了。然后后端触发我正在使用的信号,我所做的是,我使用提供的请求再次创建了表单。但是,此表单不会验证(我尝试了所有方法!!)我查了一下,我正在做与 django-registration 完全相同的事情,但它在我的代码中不起作用。

    所以我并没有真正解决问题,因为表单仍然没有验证。但是当我意识到表单已经被“注册”视图验证时,我对此感到平静。所以我现在使用 form.data[..] 而不是 form.cleaned_data[..] 这应该不是问题......

    【讨论】:

      猜你喜欢
      • 2018-06-09
      • 2019-03-06
      • 1970-01-01
      • 1970-01-01
      • 2012-06-19
      • 2015-08-29
      • 2015-07-27
      • 2016-03-12
      • 2013-10-11
      相关资源
      最近更新 更多