Django3.2.8部署后debug=False时自定义submit_line.html不生效问题
问题描述
使用Django 3.2.8部署后出现以下异常:
- 仅admin目录下的自定义
submit_line.html模板被忽略不生效,同目录下的change_form.html可正常应用 - 问题仅在
debug = False时出现,debug = True时所有自定义模板均正常加载 - 临时解决方案是将
submit_line.html的逻辑迁移到change_form.html中,同时在admin.py的render_change_form方法中手动设置所有按钮的可见性,该操作仅在debug=False时需要
项目目录结构

自定义模板代码
change_form.html
{% extends "admin/change_form.html" %} {% load i18n admin_urls %} {% block inline_field_sets %} {% for inline_admin_formset in inline_admin_formsets %} {% include inline_admin_formset.opts.template %} {% endfor %} <h3> <p>WARNING!</p> </h3> {% endblock %}
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_download_zip %} <input type="submit" value="{% trans 'zip' %}" name="_download_zip" /> {% 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 %} </div>
效果对比
| debug模式 | 页面效果 |
|---|---|
| debug=True | ![]() |
| debug=False | ![]() |
触发原因
这个差异是Django不同模式下模板加载和上下文传递的规则不同导致的,核心触发点有两个:
- 模板搜索优先级规则差异
debug=True时Django会开启模板调试模式,忽略缓存,对每个模板请求都会遍历所有APP的templates目录搜索最新的匹配文件,即使你的自定义APP排在django.contrib.admin后面,也会优先匹配到你的自定义模板。debug=False时Django会开启模板缓存,并且严格按照INSTALLED_APPS的注册顺序搜索模板,如果django.contrib.admin排在你的自定义APP前面,内置的admin/submit_line.html会被先搜索到并缓存,你的自定义模板就会被直接忽略。
而change_form.html之所以能生效,是因为你在自定义模板中显式继承了内置的change_form.html,相当于直接指定了模板加载路径,不受APP顺序的影响。 - include模板的上下文传递规则差异
debug=True时Django对模板上下文的传递规则更宽松,父模板的上下文变量会自动透传到{% include %}加载的子模板中。debug=False时如果没有显式指定with参数传递变量,子模板无法访问父模板的自定义上下文变量,你代码中的show_download_zip变量会被判定为False,按钮自然不会显示。
最优解决方案
不需要把submit_line的逻辑耦合到change_form里,按以下步骤操作即可:
- 调整INSTALLED_APPS顺序
把你存放自定义admin模板的APP移到django.contrib.admin的前面,确保模板搜索时优先匹配你自定义的文件:
# settings.py INSTALLED_APPS = [ # 存放自定义admin模板的APP,放在最前面 'your_custom_app', 'django.contrib.admin', # 剩余其他APP ]
- 显式传递上下文变量
在你的自定义change_form.html中重写submit_row块,include模板时显式传递需要的自定义变量:
{% extends "admin/change_form.html" %} {% load i18n admin_urls %} {% block inline_field_sets %} {% for inline_admin_formset in inline_admin_formsets %} {% include inline_admin_formset.opts.template %} {% endfor %} <h3> <p>WARNING!</p> </h3> {% endblock %} <!-- 新增这部分,显式传递自定义变量 --> {% block submit_row %} {% include "admin/submit_line.html" with show_download_zip=show_download_zip %} {% endblock %}
- 显式注入上下文变量
在对应的ModelAdmin中显式把show_download_zip注入到模板上下文,避免变量丢失:
# admin.py class YourModelAdmin(admin.ModelAdmin): # 你的其他配置 def changeform_view(self, request, object_id=None, form_url='', extra_context=None): extra_context = extra_context or {} # 按你的业务逻辑设置show_download_zip的取值 extra_context['show_download_zip'] = True if object_id else False return super().changeform_view(request, object_id, form_url, extra_context)
修改完成后清理Django缓存,重启服务即可在debug=False模式下正常加载自定义submit_line模板。
内容的提问来源于stack exchange,提问作者xtlc
相关产品推荐
相关产品推荐



