Django-Registration和Django-Profile,使用你自己的自定义表单

31

我正在使用django-registration和django-profile来处理注册和个人资料。我希望在注册时为用户创建个人资料。我已经创建了自定义的注册表单,并按照教程将其添加到urls.py中:

http://dewful.com/?p=70

在这个教程中的基本想法是覆盖默认的注册表单,同时创建个人资料。
forms.py - 在我的个人资料应用程序中。
from django import forms
from registration.forms import RegistrationForm
from django.utils.translation import ugettext_lazy as _
from profiles.models import UserProfile
from registration.models import RegistrationProfile

attrs_dict = { 'class': 'required' }

class UserRegistrationForm(RegistrationForm):
    city = forms.CharField(widget=forms.TextInput(attrs=attrs_dict))

    def save(self, profile_callback=None):
        new_user = RegistrationProfile.objects.create_inactive_user(username=self.cleaned_data['username'],
        password=self.cleaned_data['password1'],
        email=self.cleaned_data['email'])
        new_profile = UserProfile(user=new_user, city=self.cleaned_data['city'])
        new_profile.save()
        return new_user

在 urls.py 文件中。
from profiles.forms import UserRegistrationForm

并且

url(r'^register/$',
                           register,
                           {'backend': 'registration.backends.default.DefaultBackend', 'form_class' : UserRegistrationForm},
                           name='registration_register'),

表单已显示,我可以输入城市,但它不会保存或在数据库中创建条目。

使用信号量的解决方案 - 在这里我写了如何使用信号量来保存额外的数据 - dmitko
3个回答

29
你已经成功构建了一个自定义表单来替代默认表单,但是你试图在模型表单的save()方法中进行自定义处理。在旧版本的django-registration中这是可能的,但是我可以看出你在使用v0.8版本,因为你在URL配置中指定了一个后端。 升级指南中说:
以前,在注册期间收集数据的表单应该实现一个save()方法,该方法将创建新用户帐户。这不再是这种情况;创建帐户由后端处理,所以任何自定义逻辑都应该移动到自定义后端,或通过连接到注册过程中发送的信号来完成。
换句话说,现在表单上的save()方法被忽略了,因为你正在使用版本0.8。你需要使用自定义后端或信号来进行自定义处理。我选择创建了一个自定义后端(如果有人已经用信号让它工作,请发布代码-我无法用那种方式使它工作)。你应该能够修改这个后端以保存到你的自定义配置文件。
1. 在你的应用程序中创建regbackend.py。 2. 将DefaultBackend中的register()方法复制到其中。 3. 在该方法的末尾,查询获取相应的User实例。 4. 将额外的表单字段保存到该实例中。 5. 修改URL配置,使其同时指向自定义表单和自定义后端。

所以URL配置为:

url(r'^accounts/register/$',
    register,
    {'backend': 'accounts.regbackend.RegBackend','form_class':MM_RegistrationForm},        
    name='registration_register'
    ),

regbackend.py具有必要的导入,并且基本上是DefaultBackend的副本,只有register()方法和以下内容的添加:

    u = User.objects.get(username=new_user.username)
    u.first_name = kwargs['first_name']
    u.last_name = kwargs['last_name']
    u.save() 

1
感谢您的评论。决定在注册时进行重定向以创建个人资料,这样您就不会为未激活的用户创建个人资料了。无论如何,我将标记此问题已回答。 - ismail
我在新版本的Django注册中遇到了同样的问题。Shacker,但是“从DefaultBackend复制register()方法”具体在哪里呢?DefaultBackend在哪里?谢谢。 - Asinox
2
Asinox - 您需要从django-registration源代码中获取它。请在registration/backends/default/init.py中查找。 - shacker
太好了。我做到了,但是我的用户仍然无法从表单中获取名字和姓氏。 - Darek

12
如下所述,在Django Trac票据上的我的评论中,我创建了一个元类和mixin,允许ModelForm Django表单进行多重继承。使用这个方法,您可以轻松地创建一个表单,同时允许从用户和配置文件模型中注册字段,而无需硬编码字段或重复自己。通过使用我的元类、mixin(以及fieldset mixin),您可以这样做:
class UserRegistrationForm(metaforms.FieldsetFormMixin, metaforms.ParentsIncludedModelFormMixin, UserCreationForm, UserProfileChangeForm):
    error_css_class = 'error'
    required_css_class = 'required'
    fieldset = UserCreationForm.fieldset + [(
    utils_text.capfirst(UserProfileChangeForm.Meta.model._meta.verbose_name), {
      'fields': UserProfileChangeForm.base_fields.keys(),
    })]

    def save(self, commit=True):
        # We disable save method as registration backend module should take care of user and user
        # profile objects creation and we do not use this form for changing data
        assert False
        return None

    __metaclass__ = metaforms.ParentsIncludedModelFormMetaclass

“UserCreationForm”可以是例如“django.contrib.auth.forms.UserCreationForm”表单,“UserProfileChangeForm”可以是您的个人资料模型的简单“ModelForm”。(不要忘记在对“User”模型的外键中将“editable”设置为“False”)。
使用django-registration后端具有如下注册方法:
def register(self, request, **kwargs):
    user = super(ProfileBackend, self).register(request, **kwargs)
    profile, created = utils.get_profile_model().objects.get_or_create(user=user)

    # lambda-object to the rescue
    form = lambda: None
    form.cleaned_data = kwargs

    # First name, last name and e-mail address are stored in user object
    forms_models.construct_instance(form, user)
    user.save()

    # Other fields are stored in user profile object
    forms_models.construct_instance(form, profile)
    profile.save()

    return user

请注意,在此方法开始时(在超类中的方法中),注册信号被发送,而不是在结束时。
同样地,您可以为用户和个人资料信息制作一个更改表单。有关此示例,请参阅我在上述Django Trac票据中的评论。

1
最近我用信号(signal)实现了同样的功能,但这也太棒了!我肯定需要学习如何使用元类(metaclass)和混入(mixin)技术! - Ivan Kharlamov
您可以在此处(https://github.com/wlanslovenija/nodewatcher/blob/7480fbfef11e2ccdb7515f890bbbaa52854a24f0/nodewatcher/frontend/account/forms.py)查看其使用示例。 - Mitar

1

从0.8版本开始注册:

在您的views.py或等效文件中创建registration.backends.default.views.RegistrationView的子类:

from registration.backends.default.views import RegistrationView

class MyRegistrationView(RegistrationView):

    form_class= MyCustomRegistrationForm

    def register(self, request, **cleaned_data):
        new_user= super(MyRegistrationView, self).register(request, **cleaned_data)
        # here create your new UserProfile object
        return new_user

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接