自定义外键属性

时间:2011-07-25 19:39:55

标签: python django django-models properties django-forms

我有一个名为Personnel的模型,我将其用作User模型的配置文件模型。这是我的模特

class Personnel(models.Model):
    user = models.OneToOneField(
        User
    )
    phone = models.CharField(
        null=False, max_length=50, verbose_name="Phone"
    )

我需要在ModelForm中使用上面的模型。这是我的ModelForm

class PersonnelForm(forms.ModelForm):
    class Meta:
        model = Personnel
        exclude = ('user')

    def __init__(self, *args, **kwargs):
        personnel = Personnel(user=User.objects.create(username=(''.join(choice(ascii_uppercase + digits) for x in range(30)))))
        super(PersonnelForm, self).__init__(
             instance=personnel, *args, **kwargs
        )

我不需要在网络上显示user字段,因此我将其排除在外。但是我仍然需要为它传递一个值,所以通过传递PersonnelForm实例来启动我的PersonnelUser模式有一个名为email的字段,应由用户输入,但我无法显示此字段,因为它不是Personnel模型上的字段。

我可以创建一个名为email的虚拟字段,在设置时,设置user.email字段的值,当获取时,获取相同的值。像这样:

@property
def email():
    def fget(self):
        return 'fff'

    def fset(self, email):
        self.user.email = email

我需要以某种方式与上述代码段类似,因为我将PersonnelFormDjango's generic CRUD views一起使用。

感谢。

(请随时编辑并为标题建议一个更好的名称,以便它也可能对其他人有所帮助。)


使用丹尼尔的建议:

class PersonnelForm(forms.ModelForm):

    email = forms.EmailField(
        required=True, label=_("Email")
    )

    class Meta:
        model = Personnel
        exclude = ('user')

    def save(self, *args, **kwargs):
        commit = kwargs.get('commit', True)
        kwargs['commit'] = False
        personnel = super(PersonnelForm, self).save(*args, **kwargs)
        if not personnel.user: #To prevent creating a new user when updating.
            user = User.objects.create_user(
                email=self.cleaned_data['email'],
                username=(''.join(choice(ascii_uppercase + digits) for x in range(30))),
            )
        if commit:
            personnel.save()
        return personnel

这适用于使用ModelForm创建新记录,但我无法在更新时更新电子邮件或查看电子邮件。

1 个答案:

答案 0 :(得分:1)

你的问题有两个误解。首先,即使您已将其排除,也需要为该字段传递值;其次,您不能包含不在模型上的字段。这些都不是真的。

绝对可以定义一个单独的email字段,将其与实际模型字段一起显示在表单上,​​然后使用该值创建User对象。

鉴于您不想修改视图来执行此逻辑(IMO是错误的决定,但这是您的代码),您可以使用重写的save方法执行此操作:

class PersonnelForm(forms.ModelForm):
    email = forms.CharField()

    class Meta:
        model = Personnel
        exclude = ('user',)

    def save(self, *args, **kwargs):
        # call super method with commit=False, but remember original commit arg
        commit = kwargs.get('commit', True)
        kwargs['commit'] = False
        new_object = super(PersonnelForm, self).save(*args, **kwargs)
        user = User.objects.create_user(
            email=self.cleaned_data['user'],
            username=get_random_username(),
            password=User.objects.make_random_password()
        )
        new_object.user = user
        # now save if commit was not explicitly set to False
        if commit:
            new_object.save()
        return new_object