在Django中如何通过一次表单提交同时创建用户和用户档案

4 投票
2 回答
2765 浏览
提问于 2025-04-17 03:16

我正在使用扩展版的用户创建表单,通过我自己的模板来添加用户,这个功能运行得很好。

我还想在同一个表单模板中加入一个来自用户资料模型的自定义字段,这样在创建用户时,也能同时创建一个带有我自定义字段的用户资料。

我的做法是使用两个表单,并把它们合并到一个模板中,配上一个提交按钮。

这个表单的显示效果正是我想要的,而且返回的验证错误也很准确,但在保存到数据库时就出现了问题。当我调用用户表单的save()方法时,用户被创建了,但当我尝试保存用户资料表单时就会报错,因为此时用户还不存在,所以没有与之关联的用户。

虽然我大概明白了问题的原因,但我不知道该怎么解决,甚至不确定我采取的方法是否正确。

我把所有的代码都放在下面,包括模型、表单和视图,以便帮助大家更好地理解我想做的事情:

用户资料类 (models.py)

LEVEL = (
    ('admin', 'administrator'),
    ('team', 'team leader'),
    ('member', 'team member'),
)

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    level = models.CharField(choices=LEVEL, max_length=20)

用户创建表单和用户资料表单类 (forms.py)

class UserCreationFormExtended(UserCreationForm): 
    def __init__(self, *args, **kwargs): 
        super(UserCreationFormExtended, self).__init__(*args, **kwargs) 
        self.fields['first_name'].required = True
        self.fields['last_name'].required = True

    class Meta: 
       model = User 
       fields = ('username', 'email', 'first_name', 'last_name') 


class UserProfileForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(UserProfileForm, self).__init__(*args, **kwargs)  

         self.fields["level"].choices = ( ('admin', 'administrator'), ('team', 'team leader'), ('member', 'team member') )

    class Meta:
        model = UserProfile

use_add 视图 (views.py)

def user_add(request):

    if request.method == 'POST':
        uform = UserCreationFormExtended(request.POST)
        pform = UserProfileForm(request.POST)

        if uform.is_valid():

            uform.save()
            pform.save()

            return render_to_response('user/add_success.html', context_instance=RequestContext(request))

        else:
            return render_to_response('user/add.html', { 'uform' : uform, 'pform' : pform }, context_instance=RequestContext(request))

    else:
        uform = UserCreationFormExtended()
        pform = UserProfileForm()

        return render_to_response('user/add.html', { 'uform' : uform, 'pform' : pform }, context_instance=RequestContext(request))

2 个回答

0

我在这里找到一个类似的解决方案:http://sontek.net/blog/detail/extending-the-django-user-model

简单来说,你只需要扩展默认的用户创建表单 UserCreationForm,但保持名字不变。这样做的话,你就不需要添加新的视图或者其他东西,它和 Django 文档中关于用户资料的做法完全兼容。

老实说,我不明白他们为什么会解释如何在管理页面添加字段,却又不告诉你如何在其他地方实际使用这些字段。

8

首先,在ProfileForm的Meta类中添加 exclude = ('user',)。然后,在你的视图中:

user_valid = uform.is_valid()
profile_valid = pform.is_valid()
if user_valid and profile_valid:
    user = uform.save()
    profile = pform.save(commit=False)
    profile.user = user
    profile.save()

不过我想到,由于你在个人资料表单中只有一个字段,其实有个更简单的方法,就是完全不使用这个表单,直接把这个字段加到用户表单里:

class UserCreationFormExtended(UserCreationForm): 
    level = forms.ChoiceField(choices=LEVEL, max_length=20)
    ... etc...

if uform.is_valid():
    user = uform.save()
    profile = Profile.objects.create(user=user, level=uform.cleaned_data['level']))

撰写回答