ChatGPT解决这个技术问题 Extra ChatGPT

如何覆盖和扩展基本的 Django 管理模板?

如何在扩展管理模板(例如 admin/index.html)的同时对其进行扩展(参见 https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing-an-admin-template)?

首先 - 我知道这个问题之前已经被问过并得到了回答(参见 Django: Overriding AND extending an app template),但正如答案所说,如果您使用 app_directories 模板加载器(大多数情况下),它并不直接适用。

我目前的解决方法是制作副本并从它们扩展,而不是直接从管理模板扩展。这很好用,但是当管理模板更改时,它确实令人困惑并且增加了额外的工作。

它可以为模板考虑一些自定义扩展标签,但如果已经存在解决方案,我不想重新发明轮子。

附带说明:有人知道这个问题是否会由 Django 本身解决吗?

复制管理模板、扩展它们并覆盖/添加块是最有效的,尽管考虑到 Django 的当前状态,这不是最佳的工作流程。在三年的工作中,我还没有看到任何其他方法可以做你想做的事情:)
嗯 - 我不知道这是否是一件好事,但至少像你这样的人得出了同样的结论。听起来还不错。 :)

J
Jeff

更新:

阅读您的 Django 版本的文档。例如

https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#admin-overriding-templates https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#admin-overriding-templates https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#admin-overriding-templates

2011年的原始答案:

大约一年半前我遇到了同样的问题,我发现了一个很好的 template loader on djangosnippets.org 可以让这很容易。它允许您在特定应用程序中扩展模板,使您能够创建自己的 admin/index.html 以从管理应用程序扩展 admin/index.html 模板。像这样:

{% extends "admin:admin/index.html" %}

{% block sidebar %}
    {{block.super}}
    <div>
        <h1>Extra links</h1>
        <a href="/admin/extra/">My extra link</a>
    </div>
{% endblock %}

我已在我的网站上的 blog post 中提供了有关如何使用此模板加载器的完整示例。


以供参考;有问题的代码段已转换为 django 应用程序,可在 PyPi (pip/easy_install) 中作为 django-apptemplates 使用:pypi.python.org/pypi/django-apptemplates
只是为了 100% 明确:上述解决方案将不再适用于最新版本的 Django(至少 1.4),因为脚本使用的功能之一已被贬值。 You can find the updated source on here
请注意,对于 Django 1.8,这仍然有效,但需要以特殊方式进行设置(参见 app_namespace.Loader setup 作为示例)。 django-app-namespace-template-loader 也是 django-apptemplates 的有效替代方案,如果它可能有一天会停止工作。
这个答案对于较旧的 Django 版本非常好。但截至目前,Cheng 的另一个回答更为相关。 stackoverflow.com/a/29997719/7344164
C
Cheng

至于当前版本的 Django 1.8,无需符号链接,将 admin/templates 复制到您的项目文件夹,或按照上述答案的建议安装中间件。这是做什么:

创建如下树结构(官方文档推荐) your_project |-- your_project/ |-- myapp/ |-- templates/ |-- admin/ |-- myapp/ |-- change_form.html <- 不要拼错

注意:此文件的位置并不重要。你可以把它放在你的应用程序中,它仍然可以工作。只要它的位置可以被django发现。更重要的是 HTML 文件的名称必须与 django 提供的原始 HTML 文件名相同。

将此模板路径添加到您的 settings.py: TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(BASE_DIR, 'templates')], # <- 添加这一行 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors. auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] 确定您要覆盖的名称和块。这是通过查看 django 的 admin/templates 目录来完成的。我正在使用 virtualenv,所以对我来说,路径在这里:~/.virtualenvs/edge/lib/python2.7/site-packages/django/contrib/admin/templates/admin

在这个例子中,我想修改添加新用户表单。这个视图的模板是 change_form.html。打开 change_form.html 并找到要扩展的 {% block %}。

在您的 change_form.html 中,编写如下内容: {% extends "admin/change_form.html" %} {% block field_sets %} {# your modify here #} {% endblock %} 加载您的页面,您应该会看到变化


在不复制所有块的情况下扩展主“index.html”模板仍然不够。一种解决方案是将一些 ../ 写入“扩展”路径并指定更独特的原始路径 {% extends "../../admin/templates/admin/index.html" %}link to answer
我认为在 TEMPLATES 中我们应该使用 'DIRS': [os.path.join(BASE_DIR, 'templates')],
这是完美说明 SO 缺陷的线程类型。框架得到更新,问题不再相关,它实际上是对正确路径的威慑。很好的答案在这里。 RTFM 孩子们。
感谢您的回答。除了“这个文件的位置不重要。”,一切都很好。
g
gingerlime

如果需要覆盖admin/index.html,可以设置AdminSiteindex_template参数。

例如

# urls.py
...
from django.contrib import admin

admin.site.index_template = 'admin/my_custom_index.html'
admin.autodiscover()

并将您的模板放入 <appname>/templates/admin/my_custom_index.html


杰出的!这样做可以让您从 my_custom_index.html 执行 {% extends "admin/index.html" %} 并让其引用 django 管理模板而不复制它。谢谢你。
@Semmel 应该将此标记为正确答案,因为它是使用内置 django 功能且不需要使用自定义模板加载器的最简单方法。
m
maazza

使用 django 1.5(至少)您可以定义要用于特定 modeladmin 的模板

https://docs.djangoproject.com/en/1.5/ref/contrib/admin/#custom-template-options

你可以做类似的事情

class Myadmin(admin.ModelAdmin):
    change_form_template = 'change_form.htm'

change_form.html 是一个扩展 admin/change_form.html 的简单 html 模板(如果您想从头开始,也可以不用)


m
matyas

Chengs 的回答是正确的,但是根据管理文档,并不是每个管理模板都可以这样覆盖:https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates

每个应用程序或模型可以覆盖的模板 不是每个应用程序或模型都可以覆盖 contrib/admin/templates/admin 中的每个模板。以下可以: app_index.html change_form.html change_list.html delete_confirmation.html object_history.html 对于那些无法以这种方式覆盖的模板,您仍然可以在整个项目中覆盖它们。只需将新版本放在您的模板/管理目录中。这对于创建自定义 404 和 500 页面特别有用

我必须覆盖管理员的 login.html,因此必须将覆盖的模板放在此文件夹结构中:

your_project
 |-- your_project/
 |-- myapp/
 |-- templates/
      |-- admin/
          |-- login.html  <- do not misspell this

(在管理员中没有 myapp 子文件夹)我没有足够的声誉来评论 Cheng 的帖子,这就是为什么我不得不把它写成新的答案。


感谢您的反馈 hyneker 我希望我的回答现在更清楚、更直截了当。
是的,知道可以在项目级别自定义模板很有用,即使其中一些模板可以在应用程序级别进行可选更改。
F
Faheel

我在官方 Django 文档中找不到一个答案或一个部分,其中包含我需要覆盖/扩展默认管理模板的所有信息,所以我将这个答案写成一个完整的指南,希望它会有所帮助为将来的其他人。

假设标准的 Django 项目结构:

mysite-container/         # project container directory
    manage.py
    mysite/               # project package
        __init__.py
        admin.py
        apps.py
        settings.py
        urls.py
        wsgi.py
    app1/
    app2/
    ...
    static/
    templates/

这是您需要做的:

在 mysite/admin.py 中,创建 AdminSite 的子类: from django.contrib.admin import AdminSite class CustomAdminSite(AdminSite): # 为 `site_header`、`site_title`、`index_title` 等设置值 site_header = 'Custom Admin Site' ... # 扩展/覆盖管理视图,例如 `index()` def index(self, request, extra_context=None): extra_context = extra_context or {} # 做任何你想做的事情并将值保存在`extra_context` extra_context['world'] = 'Earth' return super(CustomAdminSite, self).index(request, extra_context) custom_admin_site = CustomAdminSite() 确保在您的应用程序的 admin.py 中导入 custom_admin_site 并注册您的模型它将它们显示在您的自定义管理站点上(如果您愿意)。在 mysite/apps.py 中,创建 AdminConfig 的子类,并将上一步中的 default_site 设置为 admin.CustomAdminSite: from django.contrib.admin.apps import AdminConfig class CustomAdminConfig(AdminConfig): default_site = 'admin.CustomAdminSite' 中mysite/settings.py,将 INSTALLED_APPS 中的 django.admin.site 替换为 apps.CustomAdminConfig(您在上一步中的自定义管理应用配置)。在 mysite/urls.py 中,将 admin.site.urls 从 admin URL 替换为 custom_admin_site.urls from .admin import custom_admin_site urlpatterns = [ ... path('admin/', custom_admin_site.urls), # for Django 1.x版本: url(r'^admin/', include(custom_admin_site.urls)), ... ] 在模板目录中创建要修改的模板,维护文档中指定的默认 Django 管理模板目录结构。例如,如果您正在修改 admin/index.html,请创建文件 templates/admin/index.html。所有现有的模板都可以通过这种方式进行修改,它们的名称和结构可以在 Django 的源代码中找到。现在,您可以通过从头开始编写模板来覆盖模板,也可以对其进行扩展,然后覆盖/扩展特定块。例如,如果您想保持一切原样但想覆盖内容块(在索引页面上列出了您注册的应用程序及其模型),请将以下内容添加到 templates/admin/index.html:{% extends 'admin/index.html' %} {% block content %}

你好,{{ world }}!

{% endblock %} 要保留块的原始内容,请在要显示原始内容的任何位置添加 {{ block.super }}:{% extends 'admin/index.html' %} {%阻止内容 %}

你好,{{ world }}!

{{ block.super }} {% endblock %} 您还可以通过修改 extrastyle 和 extrahead 块来添加自定义样式和脚本。


你有这方面的资料或文件吗?
除了我在第 5 点中添加的两个参考之外,不,我没有其他任何东西。
C
Chris Pratt

最好的方法是将 Django 管理模板放入您的项目中。因此,您的模板将在 templates/admin 中,而库存 Django 管理模板将在 template/django_admin 中。然后,您可以执行以下操作:

模板/管理员/change_form.html

{% extends 'django_admin/change_form.html' %}

Your stuff here

如果您担心库存模板保持最新,您可以将它们包含在 svn externals 或类似内容中。


使用 svn externals 是个好主意。这带来的问题是我所有的翻译人员都将翻译所有这些模板(因为 makemessages 将从所有管理模板中收集翻译字符串),如果您使用多种语言,这会增加很多额外的工作。也许有一种方法可以从 makemessages 中排除这些模板?
--ignore 参数与 makemessages 一起使用。请参阅:docs.djangoproject.com/en/dev/ref/django-admin/#makemessages
我认为另一个答案更适合我的需要。但我喜欢您的解决方案,并认为如果您不想弄乱您的模板加载器,这是一个不错的选择。
S
Saurabh Chandra Patel

对于应用程序索引,将此行添加到某个常见的 py 文件中,例如 url.py

admin.site.index_template = 'admin/custom_index.html'

对于应用程序模块索引:将此行添加到 admin.py

admin.AdminSite.app_index_template = "servers/servers-home.html"

对于更改列表:将此行添加到管理类:

change_list_template = "servers/servers_changelist.html"

对于应用程序模块表单模板:将此行添加到您的管理类

change_form_template = "servers/server_changeform.html"

等并在同一个管理员的模块类中找到其他


J
James May

我同意克里斯普拉特的观点。但我认为最好创建指向管理模板所在的原始 Django 文件夹的符号链接:

ln -s /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/ templates/django_admin

正如你所看到的,它取决于 python 版本和 Django 安装的文件夹。因此,将来或在生产服务器上,您可能需要更改路径。


m
mitchf

This 网站有一个简单的解决方案,适用于我的 Django 1.7 配置。

首先:在项目的 template/ 目录中创建一个名为 admin_src 的符号链接,指向已安装的 Django 模板。对于在 Dreamhost 上使用 virtualenv 的我来说,我的“源”Django 管理模板位于:

~/virtualenvs/mydomain/lib/python2.7/site-packages/django/contrib/admin/templates/admin

第二:在templates/中创建一个admin目录

所以我的项目的 template/ 目录现在看起来像这样:

/templates/
   admin
   admin_src -> [to django source]
   base.html
   index.html
   sitemap.xml
   etc...

第三:在新的 template/admin/ 目录中创建一个包含以下内容的 base.html 文件:

{% extends "admin_src/base.html" %}

{% block extrahead %}
<link rel='shortcut icon' href='{{ STATIC_URL }}img/favicon-admin.ico' />
{% endblock %}

第四:将您的管理员 favicon-admin.ico 添加到您的静态根 img 文件夹中。

完毕。简单的。


H
Henri Hulski

您可以使用 django-overextends,它为 Django 提供循环模板继承。

它来自 Mezzanine CMS,Stephen 从那里将其提取到一个独立的 Django 扩展中。

您可以在夹层文档中的“覆盖与扩展模板”(http://mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates)中找到更多信息。

如需更深入的了解,请查看 Stephens 博客“Django 的循环模板继承”(http://blog.jupo.org/2012/05/17/circular-template-inheritance-for-django)。

在 Google Groups 中的讨论 (https://groups.google.com/forum/#!topic/mezzanine-users/sUydcf_IZkQ) 开始了此功能的开发。

笔记:

我没有添加超过 2 个链接的声誉。但我认为这些链接提供了有趣的背景信息。所以我只是在“http(s):”之后省略了一个斜杠。也许信誉更好的人可以修复链接并删除此注释。


从 Django 1.9 开始,这个项目就不再相关了,维护者只是没有宣传它,参见 code.djangoproject.com/ticket/15053github.com/stephenmcd/django-overextends/pull/37。为了完全控制从哪个应用程序加载模板,有 django-apptemplates 和 django-app-namespace-template-loader,如果你想从一个应用程序扩展到另一个应用程序,它们仍然是相关的。