如何在ModelAdmin中动态操作Django中的表单字段?

时间:2011-05-21 17:49:05

标签: python django forms modeladmin

我有一个模型中“必需”的字段(slug),但是想要将ModelAdmin类中的字段更改为可选字段。如果用户未填写,则由另一个字段(名称)自动填写。

class SomeModel(model.Model):
  name = model.CharField(max_length=255)
  slug = model.SlugField(unique=True, max_length=255)

我尝试以各种方式执行此操作,例如在ModelAdmin中重写get_form()或使用ModelForm类并专门指定表单。

class SomeModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(self.__class__, self).get_form(request, obj, **kwargs)
        form.slug.required = False
        return form

然而,这两种解决方案都不适合我。除了手动创建表单外,还有其他更快的解决方案吗?

我有很多这些形式,手工制作可能会很乏味且难以维护。

3 个答案:

答案 0 :(得分:4)

在我自己解决同样问题时,通过Google找到此页面。以下内容也适用于ModelAdmin

def get_form(self, *args, **kwargs):
    form = super(SomeModelAdmin, self).get_form(*args, **kwargs)
    form.base_fields['slug'].required = False
    return form

根据更新的ModelFormMetaclass创建的后续表单将不再需要slug字段。

这在我的情况下效果更好,我只有一个类需要取消该字段,并且不需要在保存时进行任何数据转换。如果您有很多课程,或者需要进行数据转换,那么GoogleDroid的解决方案会更好。

答案 1 :(得分:1)

get_form方法中,form.fields['slug'].required应该有效。

但这样做的正确方法是简单地提供一个自定义的ModelForm。

class SomeModelForm(forms.ModelForm):
    slug = forms.CharField(required=False)

class SomeModelAdmin(admin.ModelAdmin):
    form = SomeModelForm

顺便说一句,请不要super(self.__class__, self)。在使用super时,您应该始终显式命名当前类,否则任何继承自您的子类并依次调用super的子类将会中断。

修改 form.fields,而不是forms.fields

通过说self.__class__,你明确地阻止Python计算继承 - 因为它总是引用具体的类 - 即继承树的底部。但是如果你的方法是那个树的中间部分,那么引用super中的具体类是错误的 - 因为你希望它从你所在的地方调用下一个级别,而不是从底部调用。这就是为什么你应该总是命名你所在的课程 - 在这种情况下,super(SomeModelAdmin, self)

答案 2 :(得分:0)

我只是想报告,以防其他人认为这有用。

我从来没有能够get_form方法做form.fields['slug'].required并且从未弄清楚原因。但是,我通过创建一个继承自ModelForm的新表单解决了我的问题。

在调用父构造函数后,我必须覆盖 init ()来设置self.fields['slug'].required = False,然后通过访问{{1}覆盖clean_slug()来修改slug字段内容}}

希望这有助于某人