使用django-profiles在个人资料表单中编辑相关模型

2 投票
2 回答
717 浏览
提问于 2025-04-16 03:43

我在我的应用中使用了 django-profiles,因为它提供了一些简单的视图,可以帮助我更快地实现目标。

不过,我遇到了一个问题。根据下面的模型,我该如何创建一个编辑个人资料的表单,包含 UserProfile 上的所有字段,以及 User 中的 first_name、last_name 和 email 字段,还有一个或多个 PhoneNumber

from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    height = models.IntegerField(_('Height'), max_length=3, blank=True, null=True, help_text=_('Users height in centimeters'))

    def get_absolute_url(self):
        return ('profiles_profile_detail', (), { 'username': self.user.username })
    get_absolute_url = models.permalink(get_absolute_url)

    def __unicode__(self):
        return self.user.username

class PhoneNumber(models.Model):
    description = models.CharField(_("Description"), max_length=32, blank=True)
    number = models.CharField(_("Phone number"), max_length=15)
    owner = models.ForeignKey(UserProfile, related_name="phone_numbers")

    def __unicode__(self):
        return u"%s (%s)" % (self.number, self.description)

到目前为止,我能做到的最接近的就是一个表单,包含了 UserProfile 上的所有字段,以及我想要的 User 字段,使用了一些在 这里这里 解释的技巧:

from django import forms
from main.models import UserProfile
from django.contrib.auth.models import User

class UserForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

class ProfileForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        # magic
        self.user = kwargs['instance'].user
        user_kwargs = kwargs.copy()
        user_kwargs['instance'] = self.user
        self.uf = UserForm(*args, **user_kwargs)
        # magic end

        super(ProfileForm, self).__init__(*args, **kwargs)

        self.fields.update(self.uf.fields)
        self.initial.update(self.uf.initial)

    def save(self, *args, **kwargs):
        # save both forms
        self.uf.save(*args, **kwargs)
        return super(ProfileForm, self).save(*args, **kwargs)

    class Meta:
        model = UserProfile
        exclude = ("user",)

在管理后台,我使用自定义的 ModelAdmin 和 Inlines,得到了我想要的 PhoneNumber 的效果,但我还没能在一个表单中重现这个效果,以便与 django-profiles 一起使用。

这到底可能吗?还是我应该放弃 django-profiles,自己写一个个人资料应用,使用表单集来引入 PhoneNumber

2 个回答

1

根据我的观察,django-profiles其实就是一组被美化过的视图。虽然我把它加到了我的应用里,但还是遇到了同样的问题。看了它的源代码后发现,它基本上没有什么特别的功能。简单来说,它只是帮你省去了自己写edit_profilecreate_profile视图的麻烦。真的,就这么简单。除非你非常害怕自己写视图,否则没必要使用django-profiles,自己写代码就好了。

1

把两个模型表单塞进同一个表单里,确实有点复杂。你可以考虑以下几种选择:

  • 自己写一个视图。你可以利用Django的URL特性,先到先得的方式来“借用”那个功能。

  • 把django-profiles放到你自己的版本控制里,随心所欲地修改,不用担心可重用性的问题。

  • 你也可以直接创建一个大表单,自己写保存的方法,然后在里面使用django-profiles。这样做会比简单地声明 fields = ('first_name', 'last_name', 'email')exclude = ("user",) 要麻烦一些。查看文档说明

这要看你的项目需求。我肯定会想自己写一个。profiles应用其实没什么复杂的,你可能会遇到其他地方需要更多控制的情况。

撰写回答