¿Cómo anular y extender las plantillas básicas de administración de Django?

126

¿Cómo anulo una plantilla de administrador (por ejemplo, admin / index.html) y al mismo tiempo la extiendo (consulte https://docs.djangoproject.com/en/dev/ref/contrib/admin/#overriding-vs-replacing -an-admin-template )?

Primero: sé que esta pregunta ya se ha hecho y respondido antes (consulte Django: Anulación y extensión de una plantilla de aplicación ), pero como dice la respuesta, no es directamente aplicable si está utilizando el cargador de plantillas app_directories (que es la mayor parte de hora).

Mi solución actual es hacer copias y extenderlas desde ellas en lugar de extenderlas directamente desde las plantillas de administración. Esto funciona muy bien, pero es realmente confuso y agrega trabajo adicional cuando cambian las plantillas de administrador.

Podría pensar en alguna etiqueta extendida personalizada para las plantillas, pero no quiero reinventar la rueda si ya existe una solución.

En una nota al margen: ¿Alguien sabe si este problema será abordado por Django?

Semmel
fuente
1
Copiar las plantillas de administración, extenderlas y anular / agregar bloques es el flujo de trabajo más eficiente, aunque no óptimo, dado el estado actual de Django. No he visto ninguna otra forma de hacer lo que intentas hacer en tres años de trabajo con él :)
Brandon
Bueno, no sé si esto es bueno o no, pero al menos personas como tú han llegado a la misma conclusión. Eso es bueno escuchar. :)
Semmel

Respuestas:

101

Actualización :

Lea los documentos para su versión de Django. p.ej

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 -plantillas

Respuesta original de 2011:

Tuve el mismo problema hace aproximadamente un año y medio y encontré un buen cargador de plantillas en djangosnippets.org que lo hace fácil. Le permite extender una plantilla en una aplicación específica, brindándole la posibilidad de crear su propia admin / index.html que extiende la plantilla admin / index.html desde la aplicación admin. Me gusta esto:

{% 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 %}

He dado un ejemplo completo sobre cómo usar este cargador de plantillas en una publicación de blog en mi sitio web.

Hey hombre
fuente
18
Para referencia; el fragmento en cuestión se ha convertido en una aplicación django, y está disponible en PyPi (pip / easy_install) como django-apptemplates: pypi.python.org/pypi/django-apptemplates
Romløk
9
Solo para ser 100% explícito: la solución anterior NO FUNCIONARÁ MÁS para las versiones recientes de Django (al menos 1.4), ya que una de las funciones que utiliza el script se deprecia. Puede encontrar la fuente actualizada aquí
OldTinfoil
2
Tenga en cuenta que con Django 1.8 esto seguirá funcionando, pero la configuración debe hacerse de una manera especial (vea app_namespace. Configuración del cargador como ejemplo). django-app-namespace-template-loader también es una alternativa funcional a django-apptemplatessi algún día puede dejar de funcionar.
Peterino
Esta respuesta fue muy buena para las versiones anteriores de Django. Pero a partir de ahora, otra respuesta de Cheng es más relevante. stackoverflow.com/a/29997719/7344164
SoftwareEnggUmar
70

En cuanto a que Django 1.8 es la versión actual, no hay necesidad de crear enlaces simbólicos, copiar las plantillas / administrador en la carpeta de su proyecto o instalar middlewares como lo sugieren las respuestas anteriores. Esto es lo que hay que hacer:

  1. cree la siguiente estructura de árbol (recomendada por la documentación oficial )

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

Nota : La ubicación de este archivo no es importante. Puede ponerlo dentro de su aplicación y seguirá funcionando. Mientras django pueda descubrir su ubicación. Lo que es más importante es que el nombre del archivo HTML debe ser el mismo que el nombre del archivo HTML original proporcionado por django.

  1. Agregue esta ruta de plantilla a su 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. Identifique el nombre y el bloque que desea anular. Esto se hace buscando en el directorio admin / templates de django. Estoy usando virtualenv, así que para mí, el camino está aquí:

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

En este ejemplo, quiero modificar el formulario para agregar un nuevo usuario. La plantilla responsable de esta vista es change_form.html . Abra change_form.html y busque el {% block%} que desea extender.

  1. En su change_form.html , escriba algo como esto:

    {% extends "admin/change_form.html" %}
    {% block field_sets %}
         {# your modification here #}
    {% endblock %}
  2. Carga tu página y deberías ver los cambios

Cheng
fuente
Todavía no es suficiente para extender la plantilla principal "index.html", sin copiar todos los bloques. Una solución es escribir algunos ../en la ruta "exentos" y especificar la ruta original más única {% extends "../../admin/templates/admin/index.html" %}. enlace para responder
hynekcer
1
Creo que en PLANTILLAS deberíamos estar usando 'DIRS': [os.path.join (BASE_DIR, 'templates')],
Raul Reyes
Este es el tipo de hilo que ilustra perfectamente la falla en SO. Se actualiza un marco y la pregunta ya no es relevante, de hecho es un elemento disuasorio del camino correcto. Gran respuesta aquí. RTFM niños.
Derek Adair
Gracias por esta respuesta Excepto por "La ubicación de este archivo no es importante", todo funcionó muy bien.
Jaswanth Manigundan
54

si necesita sobrescribir el admin/index.html, puede establecer el parámetro index_template del AdminSite.

p.ej

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

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

y coloca tu plantilla en <appname>/templates/admin/my_custom_index.html

gingerlime
fuente
55
¡Brillante! Hacer esto le permite hacerlo {% extends "admin/index.html" %}desde my_custom_index.html y tener esa referencia en la plantilla de administración de django sin copiarla. Gracias.
mattmc3
3
@Semmel debería marcar esto como la respuesta correcta, ya que es el enfoque más simple que utiliza las funciones integradas de django y no requiere el uso de cargadores de plantillas personalizados.
MrColes
9

La respuesta de Chengs es correcta, sin embargo, de acuerdo con los documentos de administración, no todas las plantillas de administración se pueden sobrescribir de esta manera: https://docs.djangoproject.com/en/1.9/ref/contrib/admin/#overriding-admin-templates

Plantillas que pueden ser anuladas por aplicación o modelo

No todas las plantillas en contrib / admin / templates / admin pueden ser anuladas por aplicación o por modelo. Lo siguiente puede:

app_index.html
change_form.html
change_list.html
delete_confirmation.html
object_history.html

Para aquellas plantillas que no pueden anularse de esta manera, aún puede anularlas para todo su proyecto. Simplemente coloque la nueva versión en su directorio de plantillas / admin . Esto es particularmente útil para crear páginas personalizadas de 404 y 500

Tuve que sobrescribir el login.html del administrador y, por lo tanto, tuve que poner la plantilla sobrescrita en la estructura de esta carpeta:

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

(sin la subcarpeta myapp en el administrador) No tengo suficiente repulsión para comentar la publicación de Cheng, es por eso que tuve que escribir esto como una nueva respuesta.

matyas
fuente
Gracias por los comentarios de hyneker. Espero que mi respuesta sea más clara y directa ahora.
matyas
Sí, es útil saber que las plantillas se pueden personalizar en el nivel del proyecto, incluso si algunas de ellas se pueden cambiar opcionalmente en el nivel de la aplicación.
hynekcer
5

La mejor manera de hacerlo es poner las plantillas de administración de Django dentro de su proyecto. Por lo tanto, sus plantillas estarán disponibles templates/adminmientras que las plantillas de administración de Django de stock estarán disponibles, por ejemplo template/django_admin. Luego, puede hacer algo como lo siguiente:

templates / admin / change_form.html

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

Your stuff here

Si le preocupa mantener actualizadas las plantillas de stock, puede incluirlas con svn externos o similares.

Chris Pratt
fuente
Usar svn externals es una gran idea. El problema que esto presenta es que todos mis traductores van a traducir todas esas plantillas (porque los mensajes de texto recopilarán las cadenas de traducción de todas las plantillas de administración), lo que agrega mucho trabajo adicional si está trabajando con varios idiomas. ¿Tal vez hay una manera de excluir esas plantillas de los mensajes de maquillaje?
Semmel
Usa el --ignoreargumento con makemessages. Ver: docs.djangoproject.com/en/dev/ref/django-admin/#makemessages
Chris Pratt
Creo que la otra respuesta se ajusta mejor a mi necesidad. Pero me gusta su solución y creo que es una buena alternativa si no quiere perder el tiempo con sus cargadores de plantillas.
Semmel
5

No pude encontrar una sola respuesta o una sección en los documentos oficiales de Django que tuviera toda la información que necesitaba para anular / extender las plantillas de administración predeterminadas, así que escribo esta respuesta como una guía completa, con la esperanza de que sea útil para otros en el futuro.

Asumiendo la estructura estándar del proyecto 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/

Esto es lo que debes hacer:

  1. En mysite/admin.py, cree una subclase de 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()

    Asegúrese de importar custom_admin_siteen admin.pysus aplicaciones y registre sus modelos para mostrarlas en su sitio de administración personalizado (si lo desea).

  2. En mysite/apps.py, crear una sub-clase de AdminConfigy conjunto default_sitea admin.CustomAdminSitepartir de la etapa anterior:

    from django.contrib.admin.apps import AdminConfig
    
    
    class CustomAdminConfig(AdminConfig):
        default_site = 'admin.CustomAdminSite'
  3. En mysite/settings.py, vuelva a colocar django.admin.siteen INSTALLED_APPSla apps.CustomAdminConfig(el administrador de configuración personalizada aplicación del paso anterior).

  4. En mysite/urls.py, reemplace admin.site.urlsde la URL del administrador acustom_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. Cree la plantilla que desea modificar en su templatesdirectorio, manteniendo la estructura predeterminada del directorio de plantillas de administración de Django como se especifica en los documentos . Por ejemplo, si estaba modificando admin/index.html, cree el archivo templates/admin/index.html.

    Todas las plantillas existentes se pueden modificar de esta manera, y sus nombres y estructuras se pueden encontrar en el código fuente de Django .

  6. Ahora puede anular la plantilla escribiéndola desde cero o extenderla y luego anular / extender bloques específicos.

    Por ejemplo, si desea mantener todo tal como está pero desea anular el contentbloqueo (que en la página de índice enumera las aplicaciones y sus modelos que registró), agregue lo siguiente a templates/admin/index.html:

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

    Para preservar el contenido original de un bloque, agregue {{ block.super }}donde quiera que se muestre el contenido original:

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

    También puede agregar estilos y scripts personalizados modificando los bloques extrastyley extrahead.

Faheel
fuente
¿tiene una fuente o documentación sobre esto?
Mary
Aparte de las dos referencias que agregué en el punto 5, no, no tengo nada más.
Faheel
1

Estoy de acuerdo con Chris Pratt. Pero creo que es mejor crear el enlace simbólico a la carpeta Django original donde se ubican las plantillas de administración:

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

y como puede ver, depende de la versión de python y de la carpeta donde instaló Django. Entonces, en el futuro o en un servidor de producción, es posible que deba cambiar la ruta.

James May
fuente
0

Esta sitio tenía una solución simple que funcionaba con mi configuración de Django 1.7.

PRIMERO: Haga un enlace simbólico llamado admin_src en la plantilla / directorio de su proyecto a sus plantillas Django instaladas. Para mí en Dreamhost usando un virtualenv, mis plantillas de administración de Django "fuente" estaban en:

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

SEGUNDO: Crear un directorio de administrador en plantillas /

Entonces la plantilla / directorio de mi proyecto ahora se veía así:

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

TERCERO: en su nuevo directorio template / admin / cree un archivo base.html con este contenido:

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

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

CUARTO: Agregue su administrador favicon-admin.ico a su carpeta img raíz estática.

Hecho. Fácil.

mitchf
fuente
0

para el índice de la aplicación, agregue esta línea a un archivo py común como url.py

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

para el índice del módulo de la aplicación: agregue esta línea a admin.py

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

para la lista de cambios: agregue esta línea a la clase admin:

change_list_template = "servers/servers_changelist.html"

para plantilla de formulario de módulo de aplicación: agregue esta línea a su clase de administrador

change_form_template = "servers/server_changeform.html"

etc. y encuentre otro en las mismas clases de módulos de administrador

Saurabh Chandra Patel
fuente
-1

Puede usar django-overextends , que proporciona herencia de plantilla circular para Django.

Proviene del Mezzanine CMS, de donde Stephen lo extrajo en una extensión independiente de Django.

Encontrará más información en "Anulación de plantillas extensibles" (http: /mezzanine.jupo.org/docs/content-architecture.html#overriding-vs-extending-templates) dentro de los documentos Mezzanine.

Para obtener información más profunda, consulte el blog de Stephens "Herencia de plantilla circular para Django" (http: /blog.jupo.org/2012/05/17/circular-template-inheritance-for-django).

Y en Grupos de Google, la discusión (https: /groups.google.com/forum / #! Topic / mezzanine-users / sUydcf_IZkQ) que inició el desarrollo de esta función.

Nota:

No tengo la reputación de agregar más de 2 enlaces. Pero creo que los enlaces proporcionan información de fondo interesante. Así que solo dejé una barra después de "http (s):". Quizás alguien con mejor reputación pueda reparar los enlaces y eliminar esta nota.

Henri Hulski
fuente
Desde Django 1.9, este proyecto no ha sido relevante, el responsable simplemente no lo anuncia, consulte code.djangoproject.com/ticket/15053 y github.com/stephenmcd/django-overextends/pull/37 . Para tomar el control completo de la aplicación desde la que se carga una plantilla, hay django-apptemplates y django-app-namespace-template-loader, que siguen siendo relevantes si desea ampliar de una aplicación a otra.
benjaoming