Django ModelForm,其中包含不在模型中的额外字段

时间:2010-02-09 12:44:42

标签: python django forms

我做了一个ModelForm,在模型中添加了一些的额外字段。保存表单时,我会使用这些字段进行一些计算。

表单上会显示额外字段,上传表单时会在POST请求中发送这些字段。问题是,当我验证表单时,它们没有添加到cleaned_data字典中。我该如何访问它们?

7 个答案:

答案 0 :(得分:21)

可以使用额外字段扩展Django ModelForm。想象一下,您有一个自定义用户模型和ModelForm

class ProfileForm(forms.ModelForm):

    class Meta:
        model = User
        fields = ['username', 'country', 'website', 'biography']

现在,想象一下你想要包含一个额外的字段(在你的用户模型中没有,让我们说一个图像头像)。通过这样做扩展您的表单:

from django import forms

class AvatarProfileForm(ProfileForm):

    profile_avatar = forms.ImageField()

    class Meta(ProfileForm.Meta):
        fields = ProfileForm.Meta.fields + ('profile_avatar',)

最后(假设表单有ImageField),请记住在视图中实例化表单时包含request.FILES

# (view.py)

def edit_profile(request):
    ...
    form = AvatarProfileForm(
        request.POST or None, 
        request.FILES or None, 
        instance=request.user
    )
    ...

希望它有所帮助。祝你好运!

编辑:

我得到了一个"只能连接元组(不是" list")到元组" AvatarProfileForm.Meta.fields属性中的错误。将其更改为元组并且有效。

答案 1 :(得分:5)

首先,你不应该有artist_id和artist字段。它们是从模型构建的。如果您需要某个艺术家姓名,请添加artist_name字段,即 CharField

此外,您正在尝试从clean_data中清除值中检索某些内容。可能没有您需要的数据 - 您应该使用self.data中的值,其中的数据直接来自POST。

答案 2 :(得分:4)

对于原始海报,这个答案可能为时已晚,但我认为这可能有助于其他人。我有同样的问题,我注意到self.cleaned_data('artist_id')可以在clean()方法中访问,但不能在clean_artist()中访问。

当我在Meta的'fields'声明中添加了额外的字段时,它就有用了。

    class Meta:
        model = Music
        fields=[..., 'artist_id']

您应该能够访问clean_artist()中的self.cleaned_data('artist_id')。

答案 3 :(得分:3)

我有一个非常相似的问题,只是看起来我做了所有必需的事情,但是在Django启动时出现了这个错误:

django.core.exceptions.FieldError: Unknown field(s) (my_new_field) specified for MyModel

这是我一个愚蠢的错误,我不小心使用 Widget 类声明了我的字段:

class MyForm(forms.ModelForm):
    my_new_field = forms.HiddenInput()

代替 Field 类:

class MyForm(forms.ModelForm):
    my_new_field = forms.CharField(widget=forms.HiddenInput())

这里没有回答眼前的问题(已经得到很好的回答),但可能会帮助其他人。

答案 4 :(得分:2)

好的,我已经解决了。似乎使用cleaning_data ['field_name']访问额外字段会引发KeyError,但使用cleaning_data.get('field_name')可以正常工作。这很奇怪,因为可以通过cleaning_data ['field_name']访问模型的正常字段。

更新:不,它不起作用。使用get()时,它不会引发KeyError,但会将值设置为None,因为额外的字段不在cleaning_data字典中。

这是代码。在模板中有一个自动完成,因此在表单中有一个“artist”字段呈现为CharField和一个隐藏的IntegerField,它将使用给定的艺术家ID自动填充。在clean_artist方法中,我想选择艺术家对象并将其存储在表单的艺术家字段中。

models.py

class Music(models.Model):
    artist = models.ForeignKey(Artist, related_name='music', blank=True, null=True)
    # other fields...

forms.py

class MusicForm(forms.ModelForm):
    artist_id = forms.IntegerField(label="", widget=forms.HiddenInput(), required=False)
    artist = forms.CharField(required=False)
    # other fields ...

    class Meta:
        model = Music

    def clean_artist(self):
        if self.cleaned_data.get('artist') == '':
            artist = None
        else:
            artist_id = self.cleaned_data.get('artist_id') # this returns always None because artist_id is not in cleaned_fields (this seemed to work with previous django versions but not with current SVN version)
            if artist_id != None:
                artist = Artist.objects.get(id=artist_id)
            else:
                artist = None

    return artist

答案 5 :(得分:1)

首先以表单的形式添加字段

class CreateForm(forms.ModelForm):

extra_field     = forms.CharField(label = 'extra_field', required = False)

现在在清理数据时,您需要从self.data中检索额外的字段 self.cleaned_data

正确

 self.data.get('extra_field')

错误

 self.cleaned_data.get('extra_field')

答案 6 :(得分:0)

在Django 2中,您可以按常规格式添加字段

class CreateCompanyForm(forms.ModelForm):

    password_confirmation = forms.CharField(
        label=translate('Password confirmation'),
        max_length=70,
        widget=forms.PasswordInput(),
        required=True,
    )
    company_name = forms.CharField(
        label="Nombre de la Compañía",
        max_length=90,
        widget=forms.TextInput(),
        required=True,
    )

    class Meta:
        model = AppUser
        fields = (
            "email",
            "first_name",
            "last_name",
            "password",
        )