在Django中,我如何从单个表单提交中同时创建用户和用户资料?

4

我正在使用扩展版的UserCreationForm通过自己的模板添加用户,这个功能运行良好。

我还想在同一表单模板中包括来自我的userprofile模型的自定义字段,以便在创建用户时也创建具有自定义字段的用户配置文件。

我的方法是使用两个表单,并将它们合并到一个模板中,带有一个提交按钮。

表单的显示效果与我想要的完全相同,并正确返回验证错误,但是当涉及保存到数据库时,它会可预测地失败。当我在用户表单上调用save()时,用户被创建了,但当我尝试保存userprofile表单时,它会抛出一个错误,因为该用户尚不存在,因此它没有关联的用户。

虽然我认为我理解了问题的原因,但我不知道如何解决它,甚至不确定我采取的方法是否正确。

为了帮助任何人更好地理解我要做什么,我在下面包括了所有我的代码,包括模型、表单和视图:

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

UserCreationForm和UserProfileForm类(forms.py)

UserCreationForm类是从Django内置的UserCreationForm类继承而来,它允许用户创建新用户。 UserProfileForm类是用于更新用户资料的表单。这两个类都定义在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

使用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个回答

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']))

谢谢!我已经看了很久了,以至于看不清楚树木。 - Finglish

0

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

基本上,你只需要扩展默认表单UserCreationForm并保持同样的名称即可。通过这样做,你不必添加任何新的视图或其他类似的东西,它可以很好地与Django文档中告诉你如何创建用户信息(UserProfiles)的方式无缝衔接。

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


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