无法在Django Admin中隐藏“保存并添加另一个”按钮

时间:2018-03-29 15:56:13

标签: django django-templates

我想在特定模型中隐藏Django管理员更改表单中的所有“保存”按钮,以满足某些条件。因此,我会覆盖相关changeform_view中的ModelAdmin方法,如下所示:

def changeform_view(self, request, object_id=None, form_url='', extra_context=None):
    extra_context = extra_context or {}
    obj = collection_management_MammalianLine.objects.get(pk=object_id)
    if obj:
        if not (request.user.is_superuser or request.user.groups.filter(name='Lab manager').exists() or request.user == obj.created_by):
            extra_context['show_save'] = False
            extra_context['show_save_and_continue'] = False
            extra_context['show_save_and_add_another'] = False
        else:
            pass
    else:
        pass
    return super(MammalianLinePage, self).changeform_view(request, object_id, extra_context=extra_context)

使用此代码,我可以成功隐藏“保存”和“保存并继续”按钮,但不能隐藏“保存并添加另一个”按钮。我可以看到submit_line.html包含以下三行

{% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" />{% endif %}
{% if show_save_and_add_another %}<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother" />{% endif %}
{% if show_save_and_continue %}<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue" />{% endif %}

我的问题是:为什么我可以隐藏“保存”和“保存并继续”按钮,而不是“保存并添加另一个”按钮?即使相关的模板标签(show_save_and_continue)在模板中。

6 个答案:

答案 0 :(得分:1)

除了show_save_and_continue之外,在传递的上下文中检查其他键。 Django always sets this directly

'show_save_and_add_another': (
        context['has_add_permission'] and not is_popup and
        (not save_as or context['add'])
    ),

您可以修补submit_row模板标记功能,首先查看context的{​​{1}}字典。

show_save_and_add_another

修改

修补&#34; admin / submit_line.html&#34;的步骤包含标记

  1. @register.inclusion_tag('admin/submit_line.html', takes_context=True) def submit_row(context): """ Display the row of buttons for delete and save. """ change = context['change'] is_popup = context['is_popup'] save_as = context['save_as'] show_save = context.get('show_save', True) show_save_and_continue = context.get('show_save_and_continue', True) show_save_and_add_another = context.get('show_save_and_add_another', False) ctx = Context(context) ctx.update({ 'show_delete_link': ( not is_popup and context['has_delete_permission'] and change and context.get('show_delete', True) ), 'show_save_as_new': not is_popup and change and save_as, 'show_save_and_add_another': ( context.get('show_save_and_add_another', None) or (context['has_add_permission'] and not is_popup and (not save_as or context['add'])) ), 'show_save_and_continue': not is_popup and context['has_change_permission'] and show_save_and_continue, 'show_save': show_save, }) return ctx templatetags

  2. 的同一级别创建models.py文件夹
  3. views.py文件夹

  4. 中创建__init__.py
  5. django/contrib/admin/templatetags/admin_modify.py复制到templatetags

  6. 使用上面的一个覆盖templatetags/admin_modify.py函数定义。

  7. 请注意这适用于 Django 2.0 及以下。

    对于最近的Django版本,找到允许此表达式为submit_row的上下文混合。例如

    False

    See values for the names used in the above expression

答案 1 :(得分:1)

我有另一种隐藏“保存并添加其他”按钮的方法。

在form.py

class TestForm(forms.ModelForm):
    class Media:
          js = ('admin/yourjsfile.js',)

在yourjsfile.js

(function($) {
'use strict';
$(document).ready(function() {
    // hide the "Save and add another" button
    $("input[name='_addanother']").attr('type','hidden');
});
})(django.jQuery);

我有同样的问题隐藏该按钮。 我在Django 1.11中测试过它确实有效,但我认为有更好的方法可以实现它。

答案 2 :(得分:1)

摘要

一些其他选项:

  1. save_as=True上设置ModelAdmin。如docs中所述,这将用“ 另存为新”按钮替换“ 保存并添加另一个”按钮。据我所知,这可能并不适合所有情况,但这是最简单的解决方案。

  2. 在您的has_add_permission上为ModelAdmin方法应用猴子补丁,因此在调用False(或super().change_view的过程中,它返回changeform_view )。

  3. 覆盖TemplateResponse.contentdocs),以从HTML中简单隐藏(或删除)包含按钮的submit-row元素。

详细说明选项1

最简单的选择是在save_as=True上设置ModelAdmin。这会将“ 保存并添加另一个”按钮替换为“ 另存为新”按钮。因此,假设其他保存按钮已被禁用,则对当前对象所做的任何更改都只能保存为新对象。当前对象将保持不变。

基本实现:

class MyModelAdmin(ModelAdmin):
    save_as = True

    # your other code here, such as the extended changeform_view 

详细说明选项2

submit_line.html模板显示了哪些上下文变量用于显示/隐藏保存和删除按钮。这些上下文变量中的大多数可以通过extra_context(或changeform_view)中的change_view进行设置。但是,正如OP所示,我们不能简单地以这种方式覆盖show_save_and_add_another

@Oluwafemi-Sule的回答所指出, 在admin_modify.py中设置了show_save_and_add_another,这为submit_line.html创建了上下文。

在仔细检查源代码时,很容易覆盖has_add_permission上下文变量,因为它确定了show_save_and_add_another的值。但是,仅将has_add_permission=False添加到extra_contextDjango < 2.1中是行不通的,因为通过ModelAdmin.render_change_form方法将撤消更改。

幸运的是,我们可以使用has_add_permission中的monkey patch来欺骗Django以使Falsechange_view,而不是覆盖模板或修补模板标签:

def change_view(self, request, object_id=None, form_url='', extra_context=None):
    # use extra_context to disable the other save (and/or delete) buttons
    extra_context = dict(show_save=False, show_save_and_continue=False, show_delete=False)
    # get a reference to the original has_add_permission method
    has_add_permission = self.has_add_permission
    # monkey patch: temporarily override has_add_permission so it returns False
    self.has_add_permission = lambda __: False
    # get the TemplateResponse from super (python 3)
    template_response = super().change_view(request, object_id, form_url, extra_context)
    # restore the original has_add_permission (otherwise we cannot add anymore)
    self.has_add_permission = has_add_permission
    # return the result
    return template_response

如果将OP(source)中的change_view替换为changeform_view,这也将起作用。

注意:很明显,只有在has_add_permission=False不影响更改视图中的其他事物的情况下,才能使用此选项。

详细说明选项3

基于此example from the docs,还可以从submit-row的呈现HTML中简单隐藏(甚至删除)change_view

def change_view(self, request, object_id=None, form_url='',
                extra_context=None):
    # get the default template response
    template_response = super().change_view(request, object_id, form_url,
                                            extra_context)
    # here we simply hide the div that contains the save and delete buttons
    template_response.content = template_response.rendered_content.replace(
        '<div class="submit-row">',
        '<div class="submit-row" style="display: none">')
    return template_response

如前所述,我们也可以完全删除submit-row部分,但这需要更多工作。

这比选项2简单,但更脆弱。

答案 3 :(得分:0)

您可以覆盖 ModelAdmin 子类中的 render_change_form 方法。 在此方法中, obj 可用作参数,您可以检查某些条件。

class OrderAdmin(admin.ModelAdmin):

    def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
        context.update({
            'show_save': False,
            'show_save_and_continue': False,
            'show_delete': False
        })
        return super().render_change_form(request, context, add, change, form_url, obj)

答案 4 :(得分:0)

我建议(更改djvg答案的选项3),使用正则表达式删除此html输入元素,如以下示例所示:

class MyModelAdmin(admin.ModelAdmin):

    def add_view(self, request, form_url='', extra_context=None):
        template_response = super(MyModelAdmin, self).add_view(
            request, form_url=form_url, extra_context=extra_context)
        # POST request won't have html response
        if request.method == 'GET':
            # removing Save and add another button: with regex
            template_response.content = re.sub("<input.*?_addanother.*?(/>|>)", "", template_response.rendered_content)
        return template_response

_addanother是此html元素的ID

答案 5 :(得分:0)

如果没有人反对,那么我会发布我的小技巧。 可以将其插入任何地方,并可以从settings文件中调用(最好在最后)。

# Hide "save_and_add_another" button
from django.contrib.admin.templatetags import admin_modify

submit_row = admin_modify.submit_row
def submit_row_custom(context):
    ctx = submit_row(context)
    ctx['show_save_and_add_another'] = False
    return ctx
admin_modify.submit_row = submit_row_custom