【问题标题】:Django ModelForm with extra fields that are not in the model带有不在模型中的额外字段的 Django ModelForm
【发布时间】:2011-01-14 19:15:07
【问题描述】:

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

额外的字段出现在表单上,​​并在上传表单时在 POST 请求中发送。问题是当我验证表单时它们没有添加到cleaned_data 字典中。如何访问它们?

【问题讨论】:

  • 它们应该被添加到cleaned_data 字典中。请发布您的表单代码,以便我们查看。
  • 如果您在后续答案中发布的代码是精确的复制粘贴,那么最后一行存在缩进问题 - 它应该是一个级别。跨度>
  • 我建议您不要将信息存储在表单字段中。更干净的解决方案是:将其存储在会话中。

标签: python django forms


【解决方案1】:

EDIT 2020(Django 2 或更高版本)

在 Django 2+ 中,您可以像这样添加额外的字段:

class ProfileForm(forms.ModelForm):
    
    extra_field = forms.ImageField()

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

原始答案(Django 1)

可以使用额外的字段扩展 Django ModelForm。想象一下,你有一个自定义的 User 模型和这个 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
    )
    ...

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

编辑:

我在 AvatarProfileForm.Meta.fields 属性中收到“只能将元组(而不是“列表”)连接到元组的错误。将其更改为元组,并且可以正常工作。

【讨论】:

  • 当我将my_new_field 添加到fields 列表时,我得到django.core.exceptions.FieldError: Unknown field(s) (my_new_field) specified for MyModel。 Django 1.10
  • 太搞笑了,问这个问题的人出过一本Django书djangobyexample.com
  • @CpILL 我遇到了同样的问题,我在下面添加了我的解决方案作为答案。
  • 只是让任何使用 Django 2、3 及更高版本的人都知道,不再需要这个技巧。您可以像使用常规表单一样在 ModelForm 中添加字段。
  • 在 django 2.2.4 中出现TypeError: can only concatenate list (not "tuple") to list 错误。您应该将第二类表单中的field 更改为列表格式。
【解决方案2】:

在 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",
        )

【讨论】:

    【解决方案3】:

    先在表单中添加字段

    class CreateForm(forms.ModelForm):
    
    extra_field     = forms.CharField(label = 'extra_field', required = False)
    

    现在在清理数据时,您需要从 self.data NOT self.cleaned_data

    中检索额外字段

    正确

     self.data.get('extra_field')
    

    错误

     self.cleaned_data.get('extra_field')
    

    【讨论】:

    • 如果您这样做,您的输入将不会被验证
    【解决方案4】:

    我遇到了一个非常相似的问题,除了看起来我做了所有必需的事情,但是当 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())
    

    这里没有回答手头的问题(已经很好地回答了),但可能对其他人有所帮助。

    【讨论】:

    • 这也是我的问题。当我需要使用forms.BooleanField() 时,我尝试使用forms.CheckboxInput() 添加字段。
    • 我尝试添加 Textarea 并犯了同样的错误!
    【解决方案5】:

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

    当我在 Meta 的“字段”声明中添加额外的字段时,它就起作用了。

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

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

    【讨论】:

      【解决方案6】:

      首先,您不应该有 Artist_id 和 Artist 字段。它们是从模型构建的。如果您需要一些艺术家姓名,请添加艺术家姓名字段,即 CharField

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

      【讨论】:

      【解决方案7】:

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

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

      这里是代码。在模板中有一个自动完成功能,因此在表单中有一个“艺术家”字段呈现为 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
      

      【讨论】:

      • 这很奇怪,因为 get 与 [] 没有什么不同。发布您的代码,将更容易找到潜在的问题。
      • 返回艺术家需要额外的缩进。它不在 clean_artist 方法中。
      • 缩进解决了问题吗?
      猜你喜欢
      • 1970-01-01
      • 2012-11-13
      • 2016-10-18
      • 2011-06-07
      • 2019-12-15
      • 2015-09-06
      • 1970-01-01
      • 1970-01-01
      • 2011-08-08
      相关资源
      最近更新 更多