从ModelForm中删除字段

9

我有一个简单的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主题。也许这与问题有关?

神奇地,它现在可以工作了,虽然我不知道为什么。无论如何,还是谢谢你的帮助。 - schneck
5个回答

15

我也遇到过同样的问题。以下是我在新版Django(trunk)中解决问题的方法:

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。上面我展示了当条件满足时显示标准表单。


2
哇,当然,这很有道理。这是我为我的使用进行调整的方式:a)用exclude = [](或任何基本排除项)初始化MyModelAdmin,然后在满足条件时执行self.exclude.append('field') - floer32
还有一点需要注意(因为它太小了我无法编辑):user.is_staff是一个属性而不是方法,所以调用它会抛出错误。 - floer32
第二个参数传递给超类方法调用应该是 obj=obj 吗? - Vikas Gulati

7

从模型创建表单 - 选择要使用的字段所述,有三种方法:

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

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

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

第三种技术看起来应该是这样的:
class MyModelForm(ModelForm):
    class Meta:
        model = MyModel
        exclude = ('field3',)

4
就像我在上面的评论中所写的那样,我必须在__init__方法中动态删除字段。因此,无法使用您建议的方法。 - schneck
“动态地”移除字段的意思是什么? - Selene
1
@Selene:这意味着在运行时确定要显示(/验证/保存)的字段,而不是在设计时确定。 - schneck
好的,你实际上想要做什么,需要在运行时更改显示哪些字段? - Selene
2
在我的项目中,有一个包含许多字段的模型,对于用户来说,可以选择他需要的字段子集。这已经很好地工作了,除了管理后端的烦人问题。 - schneck

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']

据我所知,如果在form.cleaned_data中缺少field_for_item,则其将被设置为none。请注意:这可能会删除数据库列field_for_item中的值! - guettli

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

没有,我深入代码看了一下,没有像这样的硬引用。 - schneck

0

你可以使用排除属性从一个ModelForm中移除字段

exclude = ('field_name1', 'field_name2,)

2
我知道,但我必须动态地删除字段。 - schneck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接