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


125

如何覆盖管理模板(例如admin / index.html),同时扩展它(请参阅https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing -an-admin-template)?

首先-我知道这个问题已经被问过并回答过(请参阅Django:覆盖和扩展应用程序模板),但是正如答案所言,如果您使用的是app_directories模板加载器(这是大多数时间)。

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

它可能会想到一些针对模板的自定义扩展标签,但如果已有解决方案,我不想重新发明轮子。

附带说明一下:有人知道Django本身是否可以解决此问题?


1
复制管理模板,扩展它们以及覆盖/添加块是最有效的,尽管在Django当前状态下并不是最佳的工作流程。在使用它的三年中,我还没有发现任何其他方法可以完成您想要做的事情:)
Brandon

好吧-我不知道这是否是一件好事,但至少像您这样的人也得出了相同的结论。听起来还不错。:)
Semmel 2011年

Answers:


101

更新

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

https://docs.djangoproject.com/zh-CN/1.11/ref/contrib/admin/#admin-overriding-templates https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#admin-overriding -模板

2011年的原始答案:

大约一年半以前,我遇到了同样的问题,并且在djangosnippets.org上找到了一个不错的模板加载器,可以轻松实现这一目的。它允许您在特定应用程序中扩展模板,从而使您能够创建自己的admin / index.html,从而从管理应用程序扩展admin / index.html模板。像这样:

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

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

我在我网站上的博客文章中提供了有关如何使用此模板加载器的完整示例。


18
以供参考; 所讨论的片段已被转换为一个Django应用程序,并且可在PyPI中(PIP / easy_install的)作为django的-apptemplates:pypi.python.org/pypi/django-apptemplates
Romløk

9
只是要100%明确:上述解决方案对于Django的最新版本(至少为1.4)将不再有效,因为脚本使用的功能之一已被弃用。 您可以在这里找到更新的资源
OldTinfoil 2013年

2
请注意,使用Django 1.8仍然可以使用,但需要以特殊方式进行设置(请参见app_namespace.Loader设置示例)。django-app-namespace-template-loader也可以代替django-apptemplates一天停止工作。
彼得诺(Peterino)2015年

对于较早的Django版本,此答案非常好。但是截至目前,Cheng的另一个答案更为相关。stackoverflow.com/a/29997719/7344164
SoftwareEnggUmar

70

对于最新版本的Django 1.8,无需进行符号链接,将admin / templates复制到您的项目文件夹中,也无需按照上面的答案建议安装中间件。这是做什么的:

  1. 创建以下树结构(官方文档推荐)

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

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

  1. 将此模板路径添加到您的settings.py中

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')], # <- add this line
            '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',
                ],
            },
        },
    ]
  2. 确定名称和要覆盖的块。这是通过查看django的admin / templates目录来完成的。我正在使用virtualenv,因此对我来说,路径在这里:

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

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

  1. 您的change_form.html中,编写如下内容:

    {% extends "admin/change_form.html" %}
    {% block field_sets %}
         {# your modification here #}
    {% endblock %}
  2. 加载您的页面,您应该看到更改


在不复制所有块的情况下,扩展主“ index.html”模板仍然不够。一种解决方案是将一些内容写入../“扩展”路径,并指定更独特的原始路径{% extends "../../admin/templates/admin/index.html" %}链接到答案
hynekcer 2015年

1
我认为在模板中,我们应该使用“ DIRS”:[os.path.join(BASE_DIR,'templates')],
Raul Reyes 2015年

这是一种完美说明SO缺陷的线程类型。框架得到更新,问题不再相关,实际上是对适当路径的阻碍。好答案在这里。RTFM的孩子们。
Derek Adair

感谢您的回答。除了“此文件的位置并不重要。”之外,其他所有程序都运行良好。
Jaswanth Manigundan

54

如果您需要覆盖admin/index.html,则可以设置的index_template参数AdminSite

例如

# 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


5
辉煌!这样,您便可以{% extends "admin/index.html" %}从my_custom_index.html 执行操作,并使其引用django管理模板而不进行复制。谢谢。
mattmc3 2014年

3
@Semmel应该将其标记为正确的答案,因为这是使用内置django功能的最简单方法,并且不需要使用自定义模板加载器。
MrColes 2015年


9

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

对于无法以这种方式覆盖的模板,您仍然可以在整个项目中覆盖它们。只需新版本放在您的template / admin目录中即可。这对于创建自定义404和500页特别有用

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

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

(没有admin中的myapp子文件夹)我没有足够的声誉来评论Cheng的帖子,这就是为什么我不得不将其编写为新答案。


感谢您对Hyneker的反馈,我希望我的答案现在更清晰,更直接。
matyas

是的,了解模板可以在项目级别进行自定义是很有用的,即使其中一些模板可以在应用程序级别进行可选更改也是如此。
hynekcer

5

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

templates / admin / change_form.html

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

Your stuff here

如果您担心要使库存模板保持最新状态,则可以在svn外部组件或类似工具中包含它们。


使用svn externals是一个好主意。引入的问题是我所有的翻译人员都将翻译所有这些模板(因为makemessages将从所有管理模板中收集翻译字符串),如果您使用多种语言,这会增加很多额外的工作。也许有一种方法可以将这些模板从makemessages中排除?
塞梅尔2011年

--ignore参数与一起使用makemessages。参见:docs.djangoproject.com/en/dev/ref/django-admin/#makemessages
Chris Pratt

我认为其他答案更符合我的需求。但是我喜欢您的解决方案,并且如果您不想弄乱模板加载器,那是一个不错的选择。
塞梅尔2011年

5

我找不到官方的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/

这是您需要做的:

  1. 在中mysite/admin.py,创建以下子类AdminSite

    from django.contrib.admin import AdminSite
    
    
    class CustomAdminSite(AdminSite):
        # set values for `site_header`, `site_title`, `index_title` etc.
        site_header = 'Custom Admin Site'
        ...
    
        # extend / override admin views, such as `index()`
        def index(self, request, extra_context=None):
            extra_context = extra_context or {}
    
            # do whatever you want to do and save the values in `extra_context`
            extra_context['world'] = 'Earth'
    
            return super(CustomAdminSite, self).index(request, extra_context)
    
    
    custom_admin_site = CustomAdminSite()

    确保导入custom_admin_siteadmin.py你的应用程序并注册它的模型在您的自定义管理网站显示它们(如果你愿意的话)。

  2. 在中mysite/apps.py,创建的子类,AdminConfig并从上一步中将其设置default_siteadmin.CustomAdminSite

    from django.contrib.admin.apps import AdminConfig
    
    
    class CustomAdminConfig(AdminConfig):
        default_site = 'admin.CustomAdminSite'
  3. mysite/settings.py,替换django.admin.siteINSTALLED_APPSapps.CustomAdminConfig(来自之前的步骤自定义管理应用程序配置)。

  4. 在中mysite/urls.pyadmin.site.urls从管理URL 替换为custom_admin_site.urls

    from .admin import custom_admin_site
    
    
    urlpatterns = [
        ...
        path('admin/', custom_admin_site.urls),
        # for Django 1.x versions: url(r'^admin/', include(custom_admin_site.urls)),
        ...
    ]
  5. templates目录中创建要修改的模板,并保持docs中指定的默认Django管理模板目录结构。例如,如果要修改admin/index.html,请创建文件templates/admin/index.html

    所有现有模板都可以通过这种方式进行修改,并且它们的名称和结构可以在Django的源代码中找到

  6. 现在,您可以通过从头开始编写模板来覆盖模板,也可以对其进行扩展,然后覆盖/扩展特定的块。

    例如,如果您想将所有内容保持原样但要覆盖该content块(在索引页面上列出了您注册的应用及其模型),则将以下内容添加到中templates/admin/index.html

    {% extends 'admin/index.html' %}
    
    {% block content %}
      <h1>
        Hello, {{ world }}!
      </h1>
    {% endblock %}

    要保留块的原始内容,请{{ block.super }}在希望显示原始内容的任何位置添加:

    {% extends 'admin/index.html' %}
    
    {% block content %}
      <h1>
        Hello, {{ world }}!
      </h1>
      {{ block.super }}
    {% endblock %}

    您还可以通过修改extrastyleextrahead块来添加自定义样式和脚本。


您是否有关于此的来源或文档?
玛丽

除了我在第5点中添加的两个参考文献之外,不,我没有其他东西。
Faheel

1

我同意克里斯·普拉特(Chris Pratt)的观点。但我认为最好将符号链接创建到原始Django文件夹,并将其放置在管理模板中:

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

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


0

这个站点有一个与我的Django 1.7配置一起使用的简单解决方案。

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

~/virtualenvs/mydomain/lib/python2.7/site-packages/django/contrib/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 %}

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

做完了 简单。


0

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

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

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

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

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

change_list_template = "servers/servers_changelist.html"

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

change_form_template = "servers/server_changeform.html"

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


-1

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

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

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

有关更深入的信息,请参见Stephens Blog“ Django的循环模板继承”(http:/blog.jupo.org/2012/05/17/circular-template-inheritance-for-django)。

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

注意:

我没有添加两个以上链接的声誉。但是我认为这些链接提供了有趣的背景信息。因此,我在“ http(s):”之后留了一个斜线。也许信誉较高的人可以修复链接并删除此注释。


自Django 1.9起,此项目就不相关了,维护者只是没有在宣传它,请参见code.djangoproject.com/ticket/15053github.com/stephenmcd/django-overextends/pull/37。要完全控制从哪个应用程序加载模板,有django-apptemplates和django-app-namespace-template-loader,如果要从一个应用程序扩展到另一个应用程序,它们仍然是相关的。
benjaoming
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.