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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1245214/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 21:46:22  来源:igfitidea点击:

Django admin: exclude field on change form only

pythondjangodjango-admin

提问by BlueBadger

If there a way to detect if information in a model is being added or changed.

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

If there is can this information be used to exclude fields.

如果有,此信息可用于排除字段。

Some pseudocode to illustrate what I'm talking about.

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

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

Thanks

谢谢

采纳答案by orwellian

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)

回答by Steve Pike

orwellian's answer will make the whole SubSectionAdmin singleton change its exclude property.

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

A way to ensure that fields are excluded on a per-request basis is to do something like:

确保在每个请求的基础上排除字段的方法是执行以下操作:

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)

which will just inform the Form to exclude those extra fields.

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

Not sure how this will behave given a required field being excluded...

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

回答by beruic

Setting self.excludedoes as @steve-pike mentions, make the whole SubSectionAdminsingleton change its exclude property. A singleton is a class that will reuse the same instance every time the class is instantiated, so an instance is only created on the first use of the constructor, and subsequent use of the constructor will return the same instance. See the wiki pagefor a more indept description. This means that if you write code to exclude the field on change it will have the implication that if you first add an item, the field will be there, but if you open an item for change, the field will be excluded for your following visits to the add page.

设置self.exclude就像@steve-pike 提到的那样,使整个SubSectionAdmin单例更改其排除属性。单例是一个类,每次实例化类时都会重用同一个实例,所以只有在第一次使用构造函数时才会创建一个实例,后续使用构造函数将返回同一个实例。有关更详细的描述,请参阅wiki 页面。这意味着,如果您编写代码以在更改时排除该字段,则意味着如果您首先添加一个项目,该字段将在那里,但如果您打开一个项目进行更改,该字段将在您的后续访问中被排除到添加页面。

The simplest way to achieve a per request behaviour, is to use get_fieldsand test on the objargument, which is Noneif we are adding an object, and an instance of an object if we are changing an object. The get_fieldsmethod is available from Django 1.7.

实现每个请求行为的最简单方法是使用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

Update:

更新:

Please note that get_fieldsmay return a tuple, so you may need to convert fieldsinto a list to remove elements. You may also encounter an error if the field name you try to remove is not in the list. Therefore it may, in some cases where you have other factors that exclude fields, be better to build a set of excludes and remove using a list comprehension:

请注意,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]

Alternatively you can also make a deepcopyof the result in the get_fieldsetsmethod, which in other use cases may give you access to better context for excluding stuff. Most obviously this will be useful if you need to act on the fieldset name. Also, this is the only way to go if you actually use fieldsetssince that will omit the call to get_fields.

或者,您也可以deepcopyget_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

回答by Craig Blaszczyk

The approach below has the advantage of not overriding the object wide excludeproperty; instead it is reset based on each type of request

下面的方法具有不覆盖对象范围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)