Django-Registration 与 Django-Profile,使用自定义表单

31 投票
3 回答
41647 浏览
提问于 2025-04-15 21:23

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

表单已经显示出来了,我可以输入城市名,但它没有保存或者在数据库中创建相应的记录。

3 个回答

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
12

在我对Django Trac票据的评论中,我提到我创建了一个元类和一个混入类,这样可以让Django的ModelForm表单支持多重继承。通过这个方法,你可以轻松地创建一个表单,让用户同时填写用户信息和个人资料信息,而不需要手动写出每个字段或重复代码。使用我的元类和混入类(还有字段集混入类),你可以这样做:

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票据的评论中找到。

29

你已经完成了一半的工作——成功创建了一个自定义表单来替代默认表单。不过,你现在想在模型表单上使用 save() 方法来处理一些自定义逻辑。在旧版本的 django-registration 中,这是可以做到的,但从你在 URL 配置中指定了后端来看,你现在使用的是 v0.8 版本。

升级指南中提到:

之前,注册时用来收集数据的表单需要实现一个 save() 方法,这个方法会创建新的用户账户。现在情况不一样了;创建账户的工作由后端处理,所以任何自定义逻辑都应该放到自定义后端中,或者通过连接到注册过程中的信号来实现。

换句话说,既然你已经升级到 0.8 版本,表单上的 save() 方法现在被忽略了。你需要通过自定义后端或信号来处理你的自定义逻辑。我选择创建一个自定义后端(如果有人用信号成功实现了这个,请分享代码——我没能做到)。你应该能够修改这个后端,以便保存到你的自定义用户资料中。

  1. 在你的应用中创建一个 regbackend.py 文件。
  2. 把 DefaultBackend 中的 register() 方法复制到这个文件里。
  3. 在方法的最后,查询以获取对应的用户实例。
  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() 

撰写回答