我正在尝试扩展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
。即使没有错误!那么到底出了什么问题呢?我在这个问题上花了几个小时,但我已经不知道了:(
任何帮助都是非常感激的!
form.is_valid()
失败的原因可能是因为表单的"clean_username"函数检查传递给它的用户名是否已经存在。由于信号是在创建User对象并将其添加到数据库之后发送的,因此表单每次都无法通过此测试。我的猜测是,如果您在is_valid()
返回False
之后记录form.cleaned_data
,您将获得除用户名之外的所有字段的列表。
form.data
可能不包含字段的更改值,如果form clean_函数做了任何更改(我找不到太多关于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数据,并且is_valid()
不应该总是返回false。
我知道这不是最干净的解决方案,但它避免了必须使用(可能是原始的)form.data.
好了,我想我差不多解决了。
我仍然不确定,为什么表单没有验证。但正如我所说的,我正在扩展django-registration和'register'视图已经调用了表单的is_valid(),所以我可以假设当我进一步处理发布的数据时,表单是有效的。然后视图调用后端
backend.register(request, **form.cleaned_data)
包含请求和已清理的数据(仅用户名、电子邮件和密码)。所以我不能用它来注册,因为我的附加信息丢失了。然后后端触发我正在使用的信号,我所做的是,我用提供的请求再次创建了表单。然而,这种形式将不验证(我尝试了一切!!)我查了一下,我正在做与django-registration完全相同的事情,但它在我的代码中不起作用。
所以我并没有真正解决这个问题,因为表单仍然没有验证。但当我意识到表单已经通过"注册"视图验证时,我发现了这一点。所以我使用form。data[…]]而不是form.cleaned_data[…]