【问题标题】:Cannot hide "Save and add another" button in Django Admin无法在 Django Admin 中隐藏“保存并添加另一个”按钮
【发布时间】:2018-09-08 15:58:56
【问题描述】:

当满足某些条件时,对于特定模型,我想隐藏 Django 管理员更改表单中的所有“保存”按钮。因此,我重写了相关ModelAdmin中的changeform_view方法,如下所示:

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) 在模板中。

【问题讨论】:

    标签: django django-templates


    【解决方案1】:

    您可以覆盖 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)
    

    【讨论】:

    • 不删除保存并添加另一个
    • context.update({ 'show_save_and_add_another': False }) 适用于 django 3.1
    【解决方案2】:

    编辑:

    从 Django 3.1 开始,original question 的方法应该可以正常工作:

    ...
    extra_context['show_save_and_add_another'] = False
    ...
    

    详情请见this Django commit

    旧答案:

    总结

    一些附加选项:

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

    2. ModelAdmin 上的has_add_permission 方法应用猴子补丁,因此它在调用super().change_view(或changeform_view)期间返回False

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

    详情选项 1

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

    基本实现:

    class MyModelAdmin(ModelAdmin):
        save_as = True
    
        # your other code here, such as the extended changeform_view 
    

    详情选项 2

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

    正如@Oluwafemi-Sule 的回答中指出的那样, show_save_and_add_another 设置在admin_modify.py 中,它为submit_line.html 创建上下文。

    仔细检查源代码后,很容易覆盖has_add_permission 上下文变量,因为它决定了show_save_and_add_another 的值。但是,简单地将has_add_permission=False 添加到extra_contextDjango &lt; 2.1 中不起作用,因为更改将被ModelAdmin.render_change_form 方法撤消。

    幸运的是,我们可以简单地欺骗 Django,使其认为has_add_permissionFalse,而不是覆盖模板或修补模板标签,在change_view 中使用monkey patch

    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
    

    如果您将 change_view 替换为 OP (source) 所使用的 changeform_view,这也有效。

    注意:显然,只有当has_add_permission=False 不会干扰您更改视图中的其他内容时,才能使用此选项。

    详情选项 3

    基于这个example from the docs,也可以简单地从change_view的渲染HTML中隐藏(甚至删除)submit-row

    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】:

      在传递的上下文中检查除show_save_and_continue 之外的其他键。姜戈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字典中的show_save_and_add_another

      @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
      

      编辑

      修补“admin/submit_line.html”包含标签的步骤

      1. models.pyviews.py的同级创建templatetags文件夹

      2. templatetags文件夹中创建__init__.py

      3. django/contrib/admin/templatetags/admin_modify.py 复制到templatetags/admin_modify.py

      4. 用上面的覆盖submit_row函数定义。

      注意这适用于 Django 2.0 及以下版本。

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

      has_add_permission and not is_popup and
      (not save_as or add) and can_save
      

      See values for the names used in the above expression.

      【讨论】:

      • “补丁”是什么意思?
      • 我想在这个特定的场景中,它意味着覆盖默认实现
      • 当然可以,但是怎么做?我的意思是应该把这段代码放在哪里?
      • 我的答案已编辑以显示如何修补“admin/submit_line.html”包含标签。您应该直接找到另一个答案以获得类似的结果。
      【解决方案4】:

      如果没有人反对,那么我会发布我的小技巧。 这可以插入到任何地方并从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
      

      【讨论】:

      • 感谢@Vyaches。它真的适用于我的项目。我的 django 版本是 3.1.0
      【解决方案5】:

      我有另一种方法可以隐藏“保存并添加另一个”按钮。

      在 form.py 中

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

      在你的jsfile.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 中对其进行了测试,它确实有效,但我认为有更好的方法来实现它。

      【讨论】:

        【解决方案6】:

        我建议(更改 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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-10-17
          • 2021-07-31
          • 2019-01-24
          • 1970-01-01
          • 1970-01-01
          • 2015-03-27
          • 2014-11-18
          • 2011-09-04
          相关资源
          最近更新 更多