Django 1.7,动态管理表单

3

我正在尝试在Django管理员中制作完全动态的表单。在Google中找到了像这个这个的解决方案。但是,这些解决方案对我不起作用。例如,这段代码:

class DeviceAdmin(admin.ModelAdmin):
    form = MyDeviceAdminForm
    def get_fieldsets(self, request, obj=None):
        fieldsets = super(DeviceAdmin, self).get_fieldsets(request, obj)
        fieldsets[0][1]['fields'] += ('foo',)
        return fieldsets

class MyDeviceAdminForm(forms.ModelForm):
    class Meta:
        model = Device
    def __init__(self, *args, **kwargs):
        super(MyDeviceAdminForm, self).__init__(*args, **kwargs)
        self.fields['foo'] = forms.IntegerField(label="foo")

出现了这个错误:"Unknown field(s) (item_type) specified for Device. Check fields/fieldsets/exclude attributes of class DeviceAdmin."

我找不到解决方法。我知道我需要在其他地方定义foo字段,但不知道在哪里。


您需要指定要使用哪些字段,或者排除您不想使用的字段:https://docs.djangoproject.com/en/dev/topics/forms/modelforms/#selecting-the-fields-to-use - rnevius
@rnevius 谢谢!但我不能这样做,因为我不知道要在ModelForm的Meta中显式设置哪些字段名称。这就是我的问题 - 我想根据另一个字段的初始值生成一些字段。而且我不能在ModelForm __init__方法中声明它们,因为对于ModelAdmin来说这太晚了,最终的HTML页面将缺少这些字段。 - valex
2个回答

3

Django > 1.4引入了一个变化,导致了这个问题的出现。基本上,在表单工厂之前调用get_fieldsets,然后工厂会抱怨你在get_fieldsets中引入的额外字段。幸运的是,get_fieldsets被调用了不止一次,提供了机会来改变流程。我的解决方案是在请求通过表单机制时向其添加一个标记属性:

def get_fieldsets(self, request, obj=None):
    fieldsets = super(DeviceAdmin, self).get_fieldsets(request, obj)
    if hasattr(request, "_gfs_marker"):
        fieldsets[0][1]['fields'] += ('foo',)
    setattr(request, "_gfs_marker", 1)
    return fieldsets

我处于同样的情况,不幸的是我无法理解你是如何解决它的。您介意再详细解释一下吗? - mufasa
@mufasa,ModelAdmin现在会在表单初始化之前调用get_fieldsets()两次。如果您有一个自定义表单,其__init __()定义了自定义字段,则第一次调用get_fieldsets()将抛出此错误,因为就它而言,对自定义字段的任何引用都是无效的。此修复程序会删除第一次调用中的所有自定义字段引用,但会在第二次调用后添加它们,因为它们已被定义。这有点像黑客行为,但不幸的是,这似乎是支持Django管理中的自定义表单字段的唯一方法。 - Cerin
多年过去了,这个东西刚刚拯救了我的屁股。感谢它! - Ian Price

0
如果您只是想更改对用户可见的字段名称(内部字段名称无论如何都不会可见),那么可以使用类工厂:

def get_MyDeviceAdminForm(field_name):
    class MyDeviceAdminForm(forms.ModelForm):
        my_new_field_internal = forms.CharField(label=field_name)
        class Meta:
            model = InfoLog
    return MyDeviceAdminForm
class DeviceAdmin(admin.ModelAdmin):
    form = get_MyDeviceAdminForm("Verbose name of the new field")

这在Django 1.6中有效。


谢谢,但在这里你静态定义了额外的字段,而我需要动态定义它们,它们的名称和初始值由基本字段定义。我发现Django管理员无法做到这一点,所以我只能编写自己的视图。非常感谢! - valex

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