【问题标题】:Remove fields from ModelForm从 ModelForm 中删除字段
【发布时间】:2026-02-05 14:05:01
【问题描述】:

我有一个简单的 ModelForm:

class MyForm(ModelForm):

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)
        del self.fields['name']

如您所见,我尝试从表单的字段列表中删除一个字段(该字段确实存在于模型中),但出现异常:

TemplateSyntaxError at [..]

Caught an exception while rendering: "Key 'name' not found in Form"

我没有写自定义表单,所以出现错误的模板是:

/templates/admin/includes/fieldset.html, error at line 4

有什么想法吗?

-- 更新--

问题只出现在管理区。

-- 更新 2--

也许跟踪转储会提供更多信息:

Original Traceback (most recent call last):
  File "/Library/Python/2.5/site-packages/django/template/debug.py", line 71, in render_node
    result = node.render(context)
  File "/Library/Python/2.5/site-packages/django/template/defaulttags.py", line 155, in render
    nodelist.append(node.render(context))
  File "/Library/Python/2.5/site-packages/django/template/defaulttags.py", line 239, in render
    value = bool_expr.resolve(context, True)
  File "/Library/Python/2.5/site-packages/django/template/__init__.py", line 546, in resolve
    obj = self.var.resolve(context)
  File "/Library/Python/2.5/site-packages/django/template/__init__.py", line 687, in resolve
    value = self._resolve_lookup(context)
  File "/Library/Python/2.5/site-packages/django/template/__init__.py", line 722, in _resolve_lookup
    current = current()
  File "/Library/Python/2.5/site-packages/django/contrib/admin/helpers.py", line 81, in errors
    return mark_safe(u'\n'.join([self.form[f].errors.as_ul() for f in self.fields]).strip('\n'))
  File "/Library/Python/2.5/site-packages/django/forms/forms.py", line 105, in __getitem__
    raise KeyError('Key %r not found in Form' % name)
KeyError: "Key 'name' not found in Form"

在管理区域,我使用 Grapelli 主题。也许这与问题有关?

【问题讨论】:

  • Magically™ 现在可以使用了,虽然我不知道为什么。无论如何感谢您的帮助。

标签: django


【解决方案1】:

我遇到了同样的问题。这就是我让它在新的 Django(主干)中工作的方式:

class MyModelAdmin(admin.ModelAdmin):
    # Your stuff here..

    def get_form(self, request, obj=None, **kwargs):
        if request.user.is_staff: # condition
            self.exclude = ('field',)
        return super(PublishAdmin, self).get_form(request, obj=obj, **kwargs)

通过覆盖get_form 方法并将逻辑放在这里,您可以选择要显示的Form。上面我展示了满足条件时的标准表格。

【讨论】:

  • 哇,当然,这是有道理的。这就是我对其进行调整以供我使用的方式:a) 使用 exclude = [](或任何基本排除的内容)初始化 MyModelAdmin,然后在满足条件时执行 self.exclude.append('field')
  • 也只是一个注释(我无法编辑,因为它太小了):user.is_staff 是一个属性而不是一个方法,所以调用它会抛出一个错误。
  • 不应该是obj=obj作为超类方法调用的第二个参数吗?
【解决方案2】:

Creating forms from models - Selecting the fields to use中所述,有三种方式:

  1. 在模型中,设置editable=False。从模型创建的所有表单都将排除该字段。
  2. Meta 内部类中定义fields 属性以仅包含您想要的字段。
  3. Meta 内部类中定义exclude 属性以列出您不需要的字段。

因此,如果您的模型具有字段 field1field2field3,而您不想要 field3,则技术 #2 如下所示:

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        fields = ('field1', 'field2')

技术#3 看起来像这样:

class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        exclude = ('field3',)

【讨论】:

  • 正如我在上面的评论中所写的,我必须在 init 方法中动态删除字段。因此无法使用您建议的方法。
  • “动态”删除字段是什么意思?
  • @Selene:这意味着,将显示的字段(/validated/saved)是在运行时确定的,而不是在设计时确定的
  • 好的,你到底想做什么来改变运行时显示的字段?
  • 在我的项目中,有一个模型包含许多字段,对于用户来说,可以选择他需要的字段子集。除了管理后端的烦人问题之外,这已经很好了。
【解决方案3】:

这很好用……

def __init__(self, instance, *args, **kwargs):    
    super(FormClass, self).__init__(instance=instance, *args, **kwargs)
    if instance and instance.item:
        del self.fields['field_for_item']

【讨论】:

  • AFAIK field_for_item 如果在 form.cleaned_data 中缺失,将设置为 none。注意:这可能会删除 db 列 field_for_item 中的值!
【解决方案4】:

我能想到的一个原因是,使用自定义表单的 ModelAdmin 类是否存在冲突设置。例如,如果您还在 ModelAdmin 的“fields”或“fieldsets”中明确指定了“name”字段。

【讨论】:

  • 不,我对代码进行了更深入的研究,没有像这样的硬引用。
【解决方案5】:

您可以使用 exclude 属性从 ModelForm 中删除字段

exclude = ('field_name1', 'field_name2,)

【讨论】:

  • 我知道,但我必须动态删除字段。