【问题标题】:Django: How to add a custom button to admin change form page that executes an admin action?Django:如何将自定义按钮添加到执行管理操作的管理更改表单页面?
【发布时间】:2016-04-26 03:24:47
【问题描述】:

我已经为我的模型定义了一个自定义管理操作,它可以按预期完美运行。我还查看了在 SO 上向管理员更改表单页面添加按钮的多种方法。我缺少的唯一步骤是如何使更改表单页面中的按钮使用当前对象执行我的自定义管理操作?

目标是允许管理员单独检查每个对象并对它们执行操作,而无需返回列表视图、选择检查的对象并从列表中执行操作。

我的自定义管理操作如下所示:

def admin_apply_change(modeladmin, request, queryset):
    # loop over objects in query set and perform action

我假设有一种简单而干净的方式可以在管理员更改表单中调用此操作,其中queryset 将仅包含管理员正在查看的当前打开的对象。

注意:如果按钮位于更改表单的底部,Save 按钮旁边,而不是位于顶部的 History 不太明显,那会更好。

解决方案

See the answer belowRemi 提供解决方案。为了使其正常工作,需要进行以下更正:

  1. response_change的覆盖部分变量初始化缺失:

    opts = self.model._meta
    pk_value = obj._get_pk_val()
    preserved_filters = self.get_preserved_filters(request)
    
  2. 新的包含标签custom_submit_row 应该放在模板标签中而不是管理员中(参见docs for custom templatetags

  3. 这是您可能会浪费一些时间的疏忽。在change_form.html 中,您不仅需要更改建议的行:

    {% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}
    

    还有底部更重要的一行 submit_row 出现:

    {% block submit_buttons_bottom %}{% submit_row %}{% endblock %}
    

    它位于 change_form.html 中的 javascript 块的正上方。

【问题讨论】:

    标签: django django-admin django-admin-actions


    【解决方案1】:

    您可以查看change_form_template 并将其设置为您的自定义模板并覆盖response_change 方法:

    class MyModelAdmin(admin.ModelAdmin):
    
        # A template for a customized change view:
        change_form_template = 'path/to/your/custom_change_form.html'
    
        def response_change(self, request, obj):
            opts = self.model._meta
            pk_value = obj._get_pk_val()
            preserved_filters = self.get_preserved_filters(request)
    
            if "_customaction" in request.POST:
                # handle the action on your obj
                redirect_url = reverse('admin:%s_%s_change' %
                                   (opts.app_label, opts.model_name),
                                   args=(pk_value,),
                                   current_app=self.admin_site.name)
                 redirect_url = add_preserved_filters({'preserved_filters': preserved_filters, 'opts': opts}, redirect_url)
                 return HttpResponseRedirect(redirect_url)
            else:
                 return super(MyModelAdmin, self).response_change(request, obj)
    

    从您的site-packages/django/contrib/admin/templates/change_form.html 复制change_form.html 并编辑第40 行

     {% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}
    

     {% if save_on_top %}{% block submit_buttons_top %}{% custom_submit_row %}{% endblock %}{% endif %}
    

    同时检查该行:

     {% block submit_buttons_bottom %}{% submit_row %}{% endblock %}
    

    就在 javascript 块的上方。

    然后您可以在 admin.py 的某处注册一个新的包含标签或将其添加到模板标签中:

    @register.inclusion_tag('path/to/your/custom_submit_line.html', takes_context=True)
    def custom_submit_row(context):
        """
        Displays the row of buttons for delete and save.
        """
        opts = context['opts']
        change = context['change']
        is_popup = context['is_popup']
        save_as = context['save_as']
        ctx = {
            'opts': opts,
            '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['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'],
            'is_popup': is_popup,
            'show_save': True,
            'preserved_filters': context.get('preserved_filters'),
        }
        if context.get('original') is not None:
            ctx['original'] = context['original']
        return ctx
    

    custom_submit_line.html的内容:

    {% load i18n admin_urls %}
    <div class="submit-row">
    {% if show_save %}<input type="submit" value="{% trans 'Save' %}" class="default" name="_save" />{% endif %}
    {% if show_delete_link %}
        {% url opts|admin_urlname:'delete' original.pk|admin_urlquote as delete_url %}
        <p class="deletelink-box"><a href="{% add_preserved_filters delete_url %}" class="deletelink">{% trans "Delete" %}</a></p>
    {% endif %}
    {% if show_save_as_new %}<input type="submit" value="{% trans 'Save as new' %}" name="_saveasnew" />{% 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 %}
    
    <input type="submit" value="{% trans 'Custom Action' %}"  name="_customaction" />
    
    </div>
    

    代码很多,但主要是复制/粘贴。希望对您有所帮助。

    【讨论】:

    • 谢谢。这解决了我的问题以及一些小的更正。在我的问题更新中查看它们。如果您可以更新您的答案以包含这些更正,那就太好了。
    【解决方案2】:

    大多数人可能会不假思索地这样做,尽管从答案中并不清楚是否应该简单地扩展管理员更改表单而不是完全覆盖。

    custom_change_form.html

    {% extends "admin/change_form.html" %}
    
    {% if save_on_top %}{% block submit_buttons_top %}{% custom_submit_row %}{% endblock %}{% endif %}
    
    {% block submit_buttons_bottom %}{% custom_submit_row %}{% endblock %}
    

    【讨论】:

      【解决方案3】:

      或者,您可以扩展 submit_line.html 文件,添加您的自定义按钮(在更改页面的顶部和底部)。

      您的文件 templates/adminyour_app_name/your_model_name.html 将以:

      {% extends "admin/submit_line.html" %}
      {% load i18n admin_urls %}
      <div class="submit-row">
        {% block submit-row %}  
           ... YOUR BUTTONS HERE ...
        {% endblock %}
      </div>
      

      【讨论】:

      • 我确实试过这个,但我已经有一个自定义的更改表单,所以我猜它不兼容。
      • 如果你自定义了change_form模板,我建议你直接把代码放在那个模板里面
      【解决方案4】:

      根据 Remi 的回答,一个更简洁的模板解决方案可以在 submit_line.html 模板中覆盖 submit-row

      {% extends "admin/submit_line.html" %}
      {% load i18n admin_urls %}
      <div class="submit-row">
      {% block submit-row %}
      {{ block.super }}
      
      {% if custom_buttons_template %}{% include custom_buttons_template %}{% endif %}
      
      {% endblock %}
      

      change_view 中,您可以将custom_buttons_template 添加到上下文中,这样您就可以分别自定义每个模型上的自定义按钮。

      def change_view(self, request, object_id, form_url='', extra_context=None):
          extra_context = extra_context or {}
          extra_context['custom_buttons_template'] = 'admin/test.html'
          return super(TransactionFileAdmin, self).change_view(
              request, object_id, form_url, extra_context=extra_context,
          )
      

      在此之后,我的模板将加载admin/test.html 并将内容直接插入到Save 按钮之前的提交行中。如果您想将按钮放在其他地方,您可以复制完整的submit_line.html 并将custom_buttons_template 放在任何地方。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-29
        • 2011-04-08
        • 1970-01-01
        • 1970-01-01
        • 2011-04-16
        • 2013-01-26
        • 2019-05-19
        相关资源
        最近更新 更多