具有OneToOne关系的Django模型?

时间:2010-02-13 01:34:53

标签: django django-forms

假设我使用的是默认auth.models.User以及我的自定义ProfileAddress模型,如下所示:

class Profile(models.Model):
    user = models.OneToOneField(User)
    primary_phone = models.CharField(max_length=20)
    address = models.ForeignKey("Address")

class Address(models.Model):
    country = CountryField(default='CA')
    province = CAProvinceField(default='BC')
    city = models.CharField(max_length=80)
    postal_code = models.CharField(max_length=6)
    street1 = models.CharField(max_length=80)
    street2 = models.CharField(max_length=80, blank=True, null=True)
    street3 = models.CharField(max_length=80, blank=True, null=True)

现在我想创建一个注册表单。我可以根据ModelForm创建User,但不会包含ProfileAddress的字段(这是必需的)。那么建立这种形式的最佳方式是什么?我应该甚至使用ModelForm吗?

此外,我如何使用相同的表单编辑复杂对象?我可以轻松地将一个Profile实例传回给它,它保存对必要的Address和Profile对象的引用,但是如何让它为我填写字段?

3 个答案:

答案 0 :(得分:8)

如何使用3个单独的ModelForm。一个用于Address,一个用于User,一个用于Profile,但有:{/ p>

class ProfileForm(ModelForm):
  class Meta:
    model = Profile
    exclude = ('user', 'address',)

然后,在您的视图中分别处理这3个表单。具体而言,ProfileForm使用save commit=False更新实例上的useraddress字段:

# ...
profile_form = ProfileForm(request.POST)
if profile_form.is_valid():
  profile = profile_form.save(commit=False)
  # `user` and `address` have been created previously
  # by saving the other forms
  profile.user = user
  profile.address = address

请不要犹豫,在此处使用交易,以确保只有在3个表单有效时才会插入行。

答案 1 :(得分:3)

您应该首先考虑官方推荐的扩展用户模型的方式as seen in the docs,我认为这直接来自项目经理的个人博客about the subject。 (实际的博客文章相当陈旧,现在)

至于您对表单的实际问题,请查看项目经理自己的可重用 django-profiles 应用,看看是否仔细阅读代码可以解决您的问题。特别是使用它们的these functionsthe views

编辑添加:

我已经对它进行了一些调查(因为我需要自己这样做)。似乎这样就足够了:

# apps.profiles.models

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    ...
    birth_date = models.DateField(blank=True, null=True)
    joined = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'user profile'
        verbose_name_plural = 'user profiles'
        db_table = 'user_profiles'

class Address(models.Model):
    user = models.ForeignKey(UserProfile)
    ...

# apps.profiles.forms

from django import forms
from django.forms import ModelForm
from django.forms.models import inlineformset_factory
from django.contrib.auth.models import User
from apps.profiles.models import UserProfile, Address

class UserForm(ModelForm):
    class Meta:
        model = User
        ...

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

AddressFormSet = inlineformset_factory(UserProfile, Address)

我使用“...”来剪切上面代码中的内容。我还没有对此进行测试,但是通过查看示例和表单上的文档,我认为这是正确的。

注意我将FK从Address模型放到UserProfile而不是相反,就像你的问题一样。我相信内联表单集需要它才能正常工作。

然后当然在您的视图和模板中,您将最终单独处理UserForm,UserProfileForm和AddressFormSet,但它们都可以插入到同一个表单中。

答案 2 :(得分:1)

我认为您正在寻找带有模型表单的inline formsets。这有助于您在一个页面上处理多个表单,并且还可以处理外键关系。

<强>更新

也许这个问题对你有帮助:Django: multiple models in one template using forms