news 2026/9/13 16:43:55

Django 如何覆盖第三方应用或 django.contrib.admin 的内置模板

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django 如何覆盖第三方应用或 django.contrib.admin 的内置模板

Django 如何覆盖第三方应用或 django.contrib.admin 的内置模板

【免费下载链接】djangoThe Web framework for perfectionists with deadlines.项目地址: https://gitcode.com/GitHub_Trending/dj/django

当你在项目中使用了第三方应用或django.contrib.admin这类 contrib 应用,却想改动它们自带的页面外观(比如给 admin 后台加一个 logo、改掉 admin 顶部标题)时,Django 的模板加载机制允许你用自己写的模板文件替换它们内置的模板,而不用修改这些应用的源码。本文介绍两条官方支持的路径:把覆盖模板放在项目级templates目录,或放在某个应用的templates目录,以及如何用{% extends %}只改模板中的某一块内容。适用前提是项目使用默认项目模板(django-admin startproject生成),settings.py中已有TEMPLATES设置。

先确认 TEMPLATES 设置

覆盖模板依赖两个配置项:

  • DIRS:模板引擎在文件系统上查找模板的目录列表(搜索路径),默认为空列表。
  • APP_DIRS:是否在已安装应用的内部查找模板,默认为Falsestartproject生成的默认settings.py会将其设为True

这两项的完整说明见 settings 文档,模板加载的底层机制(DIRS选项、loader 类型)见 模板 API 文档。

主路径:在项目级 templates 目录中覆盖

这是官方文档推荐的常用方式,以 How to override templates 的blog第三方应用为例。

假设第三方应用blog提供了blog/post.htmlblog/list.html两个模板。首先确保settings.pyTEMPLATES配置了DIRS,指向项目根目录下的templates目录:

from pathlib import Path BASE_DIR = Path(__file__).resolve().parent.parent INSTALLED_APPS = [ ..., "blog", ..., ] TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [BASE_DIR / "templates"], "APP_DIRS": True, # ... }, ]

如果项目是用默认项目模板创建的,TEMPLATESBASE_DIR已经存在,需要修改的只是DIRS这一项。

然后在项目根目录的templates目录里,按被覆盖模板的同名路径新建文件:

templates/ blog/ list.html post.html

工作原理:模板加载器先查找DIRS中的目录。当blog应用的视图请求blog/post.htmlblog/list.html时,加载器会返回你刚创建的文件,而不是blog应用自带的版本。这也是文档给出的行为判断依据:请求模板时拿到的是你创建的覆盖文件。

可选路径:在某个应用的 templates 目录中覆盖

由于覆盖的是项目内应用之外的模板,更常见的做法是上面的项目级目录方式;但文档同样支持把覆盖模板放进某个应用的模板目录。前提是确认APP_DIRSTrue

TEMPLATES = [ { # ... "APP_DIRS": True, # ... }, ]

如果想把blog/list.htmlblog/post.html的覆盖版本放进名为myapp的应用,目录结构为:

myapp/ templates/ blog/ list.html post.html

APP_DIRS设为True后,模板加载器会到各应用的templates目录里查找并找到这些模板。

需要注意优先级:如果应用目录和项目目录都含有同名覆盖模板,默认 Django 模板加载器会优先从项目级目录加载,即DIRS先于APP_DIRS被搜索。

覆盖 admin 模板并保留原内容

对于django.contrib.admin的模板,可以直接复制改写,也可以用{% extends %}在覆盖的同时继承原模板,只替换其中某一段。官方示例 是在 admin 首页添加自定义 logo:

{% extends "admin/base_site.html" %} {% block branding %} <img src="link/to/logo.png" alt="logo"> {{ block.super }} {% endblock %}

上面文件保存在templates/admin/base_site.html(示例中link/to/logo.png是文档示意值,请替换为你自己的 logo 路径)。文档对这段示例的要点说明:

  • 该文件位于项目级templates目录,用来覆盖admin/base_site.html
  • 新模板extends的正是被覆盖的同一个模板admin/base_site.html
  • 只替换branding这一个 block,用block.super保留原有内容;
  • 模板其余部分原样继承自admin/base_site.html

之所以可行,是因为模板加载器在解析extends标签时,不会把已经加载的那个覆盖模板(即templates/admin/base_site.html)算进去。仓库中真实的 admin 模板可以对照查看:base_site.html 和 base.html 都定义了brandingblock。

不继承、整体复制改写的做法

Django 教程第 7 部分 展示了另一种做法:直接复制admin/base_site.html再编辑。步骤是:

  1. 在项目目录(如djangotutorial)下创建templates目录;
  2. settings.pyTEMPLATES中加"DIRS": [BASE_DIR / "templates"]
  3. templates下建admin目录,把 Django 源码中的admin/base_site.html(默认 admin 模板目录位于django/contrib/admin/templates)复制进去;
  4. 编辑文件,例如把{{ site_header|default:_('Django administration') }}(连同花括号)替换为站点名称,得到一个定制的{% block branding %}

如果找不到 Django 源码在哪,文档给出的定位命令是:

$ python -c "import django; print(django.__path__)"

教程还指出:Django 任何默认 admin 模板都可以用同样方式覆盖——从默认目录复制到你的自定义目录,然后修改。另有一个边界说明:仅仅改 admin 站点标题这类定制,实际项目中更简单的方式是使用AdminSite.site_header属性,模板覆盖更适合需要改动页面结构的情况。

结果验证与注意事项

  • 验证方式:文档对覆盖生效的判断标准是加载器行为本身——当应用视图请求被覆盖的模板名时,加载器返回你在DIRS或应用templates目录中创建的文件。对 admin 而言,访问后台页面即可看到branding区域的定制内容(新 logo 或新标题)取代了默认内容。
  • 搜索顺序DIRS先于APP_DIRS,项目级目录中的同名模板会先于应用目录中的模板被找到,两处同时放同名文件时以此为准。
  • 内置表单控件模板:如果你的目标是覆盖 widget 等表单内置模板(而不是普通页面模板),必须使用TemplatesSettingrenderer,做法与本文的覆盖流程相同,详见 表单 renderer 文档中的 “Overriding built-in widget templates”。
  • 加载器适用范围:上述“默认 Django 模板加载器”的行为描述针对内置 Django 模板引擎;若项目改用 Jinja2 后端或自定义 loader,模板查找行为以对应后端为准。

参考资料:How to override templates、教程 7:模板定制章节、settings 文档。

【免费下载链接】djangoThe Web framework for perfectionists with deadlines.项目地址: https://gitcode.com/GitHub_Trending/dj/django

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 16:41:59

微信小游戏云成本失控?从架构到运营的全生命周期降本方案

做微信小游戏这三年&#xff0c;我见过太多团队栽在同一个地方&#xff1a;不是游戏不好玩&#xff0c;而是游戏上线那一刻&#xff0c;云资源的账单比流水涨得还快。立项时没人关心服务器&#xff0c;开发时一人一台压测机&#xff0c;运营时发现买量费用把利润吃光——这几乎…

作者头像 李华
网站建设 2026/9/13 16:41:39

Python数据分析面试能力体检表:20道真题拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 16:39:40

GD32H759+RT-Thread实现工控级CAN-FD实时控制

1. 为什么选 GD32H759 RT-Thread 做工控 CAN&#xff1f;不是 STM32 或 FreeRTOS 的替代&#xff0c;而是新战场的入场券 你手头刚拿到一块 GD32H759 开发板&#xff0c;芯片丝印上“H759”三个字比其他 GD 系列更粗、更亮——这不是巧合。它背后是兆易创新在 2023 年底正式量…

作者头像 李华
网站建设 2026/9/13 16:37:57

Java Swing进销存系统源码实战:库存流水与事务处理解析

简介&#xff1a;一份基于Java Swing的进销存管理系统完整源码包&#xff0c;面向计算机相关专业毕设、课程设计以及希望了解桌面管理信息系统开发的初学者。系统涵盖信息管理&#xff08;客户、商品、供应商&#xff09;、业务管理&#xff08;进货单、销售单&#xff09;、库…

作者头像 李华
网站建设 2026/9/13 16:37:56

img2threejs:电商产品图秒转Three.js 3D模型实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华