设置self.exclude 就像@steve-pike 提到的那样,使整个SubSectionAdmin 单例更改其排除属性。
单例是一个类,每次实例化时都会重用同一个实例,所以一个实例只会在第一次使用构造函数时创建,后续使用构造函数将返回相同的实例。请参阅wiki page 以获得更深入的描述。
这意味着,如果您编写代码以排除更改时的字段,这意味着如果您首先添加一个项目,该字段将在那里,但如果您打开一个项目进行更改,则该字段将被排除在您的后续访问中到添加页面。
实现每个请求行为的最简单方法是使用get_fields 并测试obj 参数,如果我们正在添加一个对象,则为None,如果我们正在更改,则为一个对象的实例一个东西。 get_fields 方法在 Django 1.7 中可用。
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]
或者,您也可以在get_fieldsets 方法中创建deepcopy 的结果,在其他用例中,这可以让您访问更好的上下文以排除内容。最明显的是,如果您需要对字段集名称进行操作,这将很有用。此外,这是您实际使用字段集的唯一方法,因为这将省略对 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