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

Posted

技术标签:

【中文标题】Django-Registration & Django-Profile,使用你自己的自定义表单【英文标题】:Django-Registration & Django-Profile, using your own custom form 【发布时间】:2011-02-05 18:53:12 【问题描述】:

我正在使用 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'),

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

【问题讨论】:

Solution with signals - 这里我写了如何使用信号来保存额外的数据 【参考方案1】:

您已经成功了——您已经成功构建了一个替换默认表单的自定义表单。但是您正在尝试使用模型表单上的 save() 方法进行自定义处理。这在旧版本的 django-registration 中是可能的,但我可以从您在 URL conf 中指定后端的事实中看出,您使用的是 v0.8。

upgrade guide 说:

以前,用于收集的表单 注册期间的数据是预期的 实现一个 save() 方法 将创建新的用户帐户。 这已不再是这种情况;创造 该帐户由后端处理, 所以任何自定义逻辑都应该是 移动到自定义后端,或通过 将侦听器连接到信号 在注册过程中发送。

换句话说,现在您使用的是 0.8 版,表单上的 save() 方法将被忽略。您需要使用自定义后端或信号进行自定义处理。我选择创建一个自定义后端(如果有人使用信号进行此操作,请发布代码 - 我无法让它以这种方式工作)。您应该能够修改它以保存到您的自定义配置文件中。

    在您的应用中创建一个 regbackend.py。 将 DefaultBackend 中的 register() 方法复制到其中。 在方法结束时,进行查询以获取对应的 User 实例。 将其他表单字段保存到该实例中。 修改 URL conf 使其同时指向自定义表单和自定义后端

所以 URL conf 是:

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() 

【讨论】:

感谢您的评论。决定在注册时进行重定向以创建个人资料,这样您就没有未激活用户的个人资料。但是会将此问题标记为已回答。 新版djando注册也有同样的问题。 Shacker,但具体在哪里:“将 register() 方法从 DefaultBackend 复制到其中。” DefaultBackend??,在哪里?谢谢 Asinox - 您需要从 django-registration 源代码中获取它。查看registration/backends/default/__init__.py 这很棒。我做到了,但我的用户仍然无法从表单中获取 first_name 和 last_name。【参考方案2】:

如my comment on Django Trac ticket 中所述,我创建了一个元类和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 票证的评论中找到这方面的示例。

【讨论】:

我最近用信号实现了同样的东西,但这真是太棒了!我绝对需要学习如何使用元类和混合技术! 你可以看到here的一个使用例子。【参考方案3】:

注册 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

【讨论】:

以上是关于Django-Registration & Django-Profile,使用你自己的自定义表单的主要内容,如果未能解决你的问题,请参考以下文章

Django-Registration:电子邮件作为用户名

包含 django-registration 的 url

django-registration 与 paypal 集成

django-registration 和 CSS 文件

为 django 1.5 自定义用户模型子类化 django-registration 1.0 表单

django-registration 中的 Urls 配置