如何在Django中创建一个UserProfile表单,包含对名字和姓氏的修改?

25

我认为我的问题非常明显,几乎每个使用 UserProfile 的开发人员都应该能够回答它。

然而,我在 Django 文档或《Django Book》中找不到任何帮助。

当您想要在 Django Forms 中创建一个 UserProfile 表单时,您希望修改配置文件字段以及某些 User 字段。

但是,目前还没有 forms.UserProfileForm (还没有吗?)!

那么,如何实现呢?

7个回答

41

我今天偶然发现了这个问题,经过一些搜索,我找到了一个在我看来更加简洁的解决方案:

#in forms.py
class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ["username", "email"]

class UserProfileForm(forms.ModelForm):
    class Meta:
        model = UserProfile

#in views.py
def add_user(request):
    ...
    if request.method == "POST":
        uform = UserForm(data = request.POST)
        pform = UserProfileForm(data = request.POST)
        if uform.is_valid() and pform.is_valid():
            user = uform.save()
            profile = pform.save(commit = False)
            profile.user = user
            profile.save()
            ....
    ...

#in template
<form method="post">
    {{ uform.as_p }}
    {{ pform.as_p }}
    <input type="submit" ...>
</form>

来源


这是另一种解决方案,但您无法按照自己的意愿对字段进行排序。例如,我有一个title字段,它应该在first_namelast_name之前,但仍然属于pform - Natim
Natim,你可以这样做 - 但需要用手动完成 :) - Nikita Hismatov
你可以指定字段的顺序,就像ns-keip提到的那样,只要你自己进行渲染。https://docs.djangoproject.com/en/1.8/topics/forms/#rendering-fields-manually - Max.Mirkia
我该如何让密码1和密码2在用户注册中起作用?只有“密码”可用。 - Raven

35

这是我最终的做法:

class UserProfileForm(forms.ModelForm):
    first_name = forms.CharField(label=_(u'Prénom'), max_length=30)
    last_name = forms.CharField(label=_(u'Nom'), max_length=30)

    def __init__(self, *args, **kw):
        super(UserProfileForm, self).__init__(*args, **kw)
        self.fields['first_name'].initial = self.instance.user.first_name
        self.fields['last_name'].initial = self.instance.user.last_name

        self.fields.keyOrder = [
            'first_name',
            'last_name',
            ...some_other...
            ]

    def save(self, *args, **kw):
        super(UserProfileForm, self).save(*args, **kw)
        self.instance.user.first_name = self.cleaned_data.get('first_name')
        self.instance.user.last_name = self.cleaned_data.get('last_name')
        self.instance.user.save()

    class Meta:
        model = UserProfile

在原文中提到“Media”的地方应该改为“Meta”。 - Daishiman
这个解决方案在配置文件尚未创建时无法正常工作。我目前还没有修复它的方法,但是一旦我找到了,我会发布它。 - Justin Hamade
5
如果按照这里描述的方式,在User模型上使用post_save信号,就不会出现这种情况。详情请参见:http://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users。 - Natim
更多关于信号设置的信息请参考这里:https://dev59.com/oUrSa4cB1Zd3GeqPZtd0#1909719 - Natim
从Django 1.5开始,您可以直接使用AUTH_USER_MODEL :) https://docs.djangoproject.com/en/dev/topics/auth/customizing/#substituting-a-custom-user-model - Natim

5
这是我在当前主干(修订版:11804)中的做法。Natim的解决方案对我不起作用。
admin.py中:
class ProfileAdmin(admin.ModelAdmin):
    form = ProfileForm

    def save_model(self, request, obj, form, change):
        obj.user.first_name = form.cleaned_data['first_name']
        obj.user.last_name = form.cleaned_data['last_name']
        obj.user.save()
        obj.save()

forms.py 文件中:
class ProfileForm(forms.ModelForm):
    first_name = forms.CharField(max_length=256)
    last_name = forms.CharField(max_length=256)

    def __init__(self, *args, **kwargs):
        super(ProfileForm, self).__init__(*args, **kwargs)
        try:
            self.fields['first_name'].initial = self.instance.user.first_name
            self.fields['last_name'].initial = self.instance.user.last_name
        except User.DoesNotExist:
            pass

    class Meta:
         fields = ['first_name', 'last_name', ...etc.]

但是使用您的ProfileForm,您无法保存个人资料。 我的不会修改管理员。但是您的可以,但是没有管理员无法使用。 - Natim
它会通过obj.save()保存配置文件。你是正确的,它只在管理界面中起作用。我不得不将其构建到其中。要使其在应用程序视图中起作用,您应该将逻辑从管理界面移动到表单中。就像你在save方法中所做的那样。 - wunki

1
这是我在很久以前的一个项目中使用的东西,希望能对那些在搜索此问题的人有所帮助。
class SignUpForm(forms.ModelForm):
    first_name = forms.CharField(max_length = 30)
    last_name = forms.CharField(max_length = 30)
    username = forms.CharField(max_length = 30)
    password = forms.CharField(widget = forms.PasswordInput)
    password1 = forms.CharField(widget = forms.PasswordInput)
    class Meta:
        model = UserProfile
        exclude = ['user']

    def clean_username(self): # check if username does not exist before
        try:
            User.objects.get(username=self.cleaned_data['username']) #get user from user model
        except User.DoesNotExist :
            return self.cleaned_data['username']

        raise forms.ValidationError("This user exist already choose an0ther username")



    def clean(self, *args , **kwargs):
        super(SignUpForm).clean(*args ,**kwargs) # check if password 1 and password2 match each other
        if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:#check if both pass first validation
            if self.cleaned_data['password1'] != self.cleaned_data['password2']: # check if they match each other
                raise forms.ValidationError("Passwords don't match each other")

        return self.cleaned_data
    def save(self): # create new user
        new_user = User.objects.create_user(username=self.cleaned_data['username'],password=self.cleaned_data['password1'],email=self.cleaned_data['email'])
        new_user.first_name = self.cleaned_data['first_name']
        new_user.last_name = self.cleaned_data['last_name']
        new_user.save()
        UserProf =  super(SignUpForm,self).save(commit = False)
        UserProf.user = new_user
        UserProf.save()
        return UserProf

1

这是无用的,因为您不能从UserProfile和Django User模型创建组合表单集。 - Denis

0
为什么不在后端使用两个模型表单,然后在模板中将它们呈现为一个单一的表单呢?从您的UserProfileForm中删除名称字段,并为用户对象创建第二个模型表单。

这不是一个坏主意。但只有一个表格更方便。 - Natim
不同的方法吧。我选择了上面描述的方式,因为使用多个Django表单对象更方便,它们可以独立于彼此重复使用(处理比你上面的方法更干净(在我看来))。明确一下,我不是在谈论页面上的多个HTML表单;对用户来说,它看起来像一个表单。 - Tom

0

如果您将两个模型合并到一个表单中,我认为在文档中找不到任何信息是正常的。

或者,您可以很明显地创建两个模型表单,一个用于用户,另一个用于用户配置文件。将用户配置文件模型表单设置为仅显示名字和姓氏。将两个表单放在同一个模板中,在单个<form>标记内。提交表单时,调用每个表单的保存方法。


是的,但实际上使用两个表单并不是很直接。使用这种解决方案,您无法按照想要的顺序排序字段并继续使用 {{form}}。使用我提供的解决方案,您可以随心所欲地进行操作,并继续使用表单框架。 - Natim
我只是不喜欢在模型表单中合并两个模型的想法。除了我的主观意见外,我没有具体反对你的解决方案,而且似乎这两种解决方案都有其优缺点。随意使用 ;) - shanyu
我同意你的观点,但这取决于你寻找特定问题的角度。UserProfile模型和User模型密切相关。对我来说,UserProfile模型只是向User模型添加一些缺失字段的一种方式。当您想要更新您的个人资料时,您希望更新所有这些字段,而不管它们是在UserProfile还是User模型中,因为它们合并在一起以存储有关用户的属性。 - Natim

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