Django admin:仅在更改表单中排除字段

时间:2009-08-07 14:52:53

标签: django-admin

如果有办法检测是否正在添加或更改模型中的信息。

如果可以使用此信息来排除字段。

一些假代码来说明我在说什么。

class SubSectionAdmin(admin.ModelAdmin):
    if something.change_or_add = 'change':
        exclude = ('field',)
    ...

由于

4 个答案:

答案 0 :(得分:15)

orwellian的答案将使整个SubSectionAdmin单例改变其排除属性。

确保按请求排除字段的方法是执行以下操作:

class SubSectionAdmin(admin.ModelAdmin):
    # ...
    def get_form(self, request, obj=None, **kwargs):
        """Override the get_form and extend the 'exclude' keyword arg"""
        if obj:
            kwargs.update({
                'exclude': getattr(kwargs, 'exclude', tuple()) + ('field',),
            })
        return super(SubSectionAdmin, self).get_form(request, obj, **kwargs)

只会通知表格排除那些额外的字段。

如果排除了必填字段,则不确定这将如何表现......

答案 1 :(得分:7)

self.exclude设置为@ steve-pike提及,使整个SubSectionAdmin单例更改其排除属性。 单例是一个类,它将在每次实例化类时重用相同的实例,因此实例仅在第一次使用构造函数时创建,并且后续使用构造函数将返回相同的实例。有关更详细的说明,请参阅wiki page。 这意味着如果您编写代码以在更改时排除字段,则意味着如果您首先添加项目,该字段将在那里,但如果您打开要更改的项目,则该字段将被排除在您的后续访问中到添加页面。

实现每个请求行为的最简单方法是使用get_fields并测试obj参数,如果我们要添加一个对象,则为None,并且实例为如果我们要更改对象,则为对象。可以从Django 1.7获得get_fields方法。

class SubSectionAdmin(admin.ModelAdmin):
    def get_fields(self, request, obj=None):
        fields = super(SubSectionAdmin, self).get_fields(request, obj)
        if obj:  # obj will be None on the add page, and something on change pages
            fields.remove('field')
        return fields

<强>更新

请注意,get_fields可能会返回一个元组,因此您可能需要将fields转换为列表以删除元素。 如果您尝试删除的字段名称不在列表中,则可能还会遇到错误。因此,在某些情况下,如果您有其他排除字段的因素,最好使用列表理解构建一组排除和删除:

class SubSectionAdmin(admin.ModelAdmin):
    def get_fields(self, request, obj=None):
        fields = list(super(SubSectionAdmin, self).get_fields(request, obj))
        exclude_set = set()
        if obj:  # obj will be None on the add page, and something on change pages
            exclude_set.add('field')
        return [f for f in fields if f not in exclude_set]

或者,您也可以在deepcopy方法中生成get_fieldsets结果,在其他用例中,您可以访问更好的上下文以排除内容。最明显的是,如果您需要对字段集名称进行操作,这将非常有用。此外,如果您实际使用字段集,这是唯一的方法,因为这将省略对get_fields的调用。

from copy import deepcopy

class SubSectionAdmin(admin.ModelAdmin):
    def get_fieldsets(self, request, obj=None):
        """Custom override to exclude fields"""
        fieldsets = deepcopy(super(SubSectionAdmin, self).get_fieldsets(request, obj))

        # Append excludes here instead of using self.exclude.
        # When fieldsets are defined for the user admin, so self.exclude is ignored.
        exclude = ()

        if not request.user.is_superuser:
            exclude += ('accepted_error_margin_alert', 'accepted_error_margin_warning')

        # Iterate fieldsets
        for fieldset in fieldsets:
            fieldset_fields = fieldset[1]['fields']

            # Remove excluded fields from the fieldset
            for exclude_field in exclude:
                if exclude_field in fieldset_fields:
                    fieldset_fields = tuple(field for field in fieldset_fields if field != exclude_field)  # Filter
                    fieldset[1]['fields'] = fieldset_fields  # Store new tuple

        return fieldsets

答案 2 :(得分:6)

class SubSectionAdmin(admin.ModelAdmin):
    # ...
    def change_view(self, request, object_id, extra_context=None):       
        self.exclude = ('field', )
        return super(SubSectionAdmin, self).change_view(request, object_id, extra_context)

答案 3 :(得分:0)

以下方法的优点是不会覆盖对象范围exclude属性;相反,它会根据每种类型的请求重置

class SubSectionAdmin(admin.ModelAdmin):
    add_exclude = ('field1', 'field2')
    edit_exclude = ('field2',)

    def add_view(self, *args, **kwargs):
        self.exclude = getattr(self, 'add_exclude', ())
        return super(SubSectionAdmin, self).add_view(*args, **kwargs)

    def change_view(self, *args, **kwargs):
        self.exclude = getattr(self, 'edit_exclude', ())
        return super(SubSectionAdmin, self).change_view(*args, **kwargs)