Personalizar el Sitio de Administración de Django

DjangoDjangoBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

Este tutorial comienza donde dejó Agregar una hoja de estilos y una imagen. Continuaremos con la aplicación de encuestas web y nos centraremos en personalizar el sitio de administración automáticamente generado por Django que primero exploramos en Configurar la base de datos.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL django(("Django")) -.-> django/DevelopmentandAdministrationToolsGroup(["Development and Administration Tools"]) django(("Django")) -.-> django/DatabaseModelsandMigrationsGroup(["Database, Models, and Migrations"]) django(("Django")) -.-> django/UserInterfaceandInteractionGroup(["User Interface and Interaction"]) django/DatabaseModelsandMigrationsGroup -.-> django/models("Models") django/DatabaseModelsandMigrationsGroup -.-> django/databases("Databases") django/DatabaseModelsandMigrationsGroup -.-> django/schemaeditor("SchemaEditor") django/UserInterfaceandInteractionGroup -.-> django/templates("Templates") django/DevelopmentandAdministrationToolsGroup -.-> django/django_admin("Django Admin") django/DevelopmentandAdministrationToolsGroup -.-> django/contrib_packages("Contrib Packages") subgraph Lab Skills django/models -.-> lab-153747{{"Personalizar el Sitio de Administración de Django"}} django/databases -.-> lab-153747{{"Personalizar el Sitio de Administración de Django"}} django/schemaeditor -.-> lab-153747{{"Personalizar el Sitio de Administración de Django"}} django/templates -.-> lab-153747{{"Personalizar el Sitio de Administración de Django"}} django/django_admin -.-> lab-153747{{"Personalizar el Sitio de Administración de Django"}} django/contrib_packages -.-> lab-153747{{"Personalizar el Sitio de Administración de Django"}} end

Personalizar el formulario de administración

Al registrar el modelo Question con admin.site.register(Question), Django fue capaz de construir una representación predeterminada del formulario. A menudo, querrás personalizar cómo se ve y funciona el formulario de administración. Lo harás indicando a Django las opciones que quieres cuando registras el objeto.

Veamos cómo funciona reordenando los campos en el formulario de edición. Reemplaza la línea admin.site.register(Question) con:

Edita el archivo ~/project/mysite/polls/admin.py para que se vea así:

from django.contrib import admin

from.models import Question


class QuestionAdmin(admin.ModelAdmin):
    fields = ["pub_date", "question_text"]


admin.site.register(Question, QuestionAdmin)

Seguirás este patrón: crear una clase de administración de modelo y luego pasarla como segundo argumento a admin.site.register() cada vez que necesites cambiar las opciones de administración de un modelo.

Ejecuta el servidor de desarrollo de Django:

cd ~/project/mysite
python manage.py runserver

Abre http://127.0.0.1:8000/admin/ en Firefox del Entorno de Escritorio y haz clic en el enlace "Questions". Deberías ver un formulario que se ve así.

Este cambio en particular hace que la "Fecha de publicación" aparezca antes del campo "Question":

Admin form field reorder

Esto no es impresionante con solo dos campos, pero para formularios de administración con docenas de campos, elegir un orden intuitivo es un detalle de usabilidad importante.

Y hablando de formularios con docenas de campos, es posible que desees dividir el formulario en conjuntos de campos:

from django.contrib import admin

from.models import Question


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["question_text"]}),
        ("Información de fecha", {"fields": ["pub_date"]}),
    ]


admin.site.register(Question, QuestionAdmin)

El primer elemento de cada tupla en ~django.contrib.admin.ModelAdmin.fieldsets es el título del conjunto de campos. Así se ve nuestro formulario ahora:

Admin form with fieldsets

Agregar objetos relacionados

Está bien, tenemos nuestra página de administración de Question, pero una Question tiene múltiples Choice, y la página de administración no muestra las opciones.

Todavía no.

Hay dos maneras de resolver este problema. La primera es registrar Choice con el administrador de la misma manera que hicimos con Question:

from django.contrib import admin

from.models import Choice, Question

#...
admin.site.register(Choice)

Ahora, "Opciones" es una opción disponible en el administrador de Django. El formulario "Agregar opción" se ve así:

Add Choice form interface

En ese formulario, el campo "Pregunta" es un cuadro de selección que contiene cada pregunta en la base de datos. Django sabe que un ~django.db.models.ForeignKey debe representarse en el administrador como un <select>. En nuestro caso, solo existe una pregunta en este momento.

También observe el enlace "Agregar otra pregunta" junto a "Pregunta". Todo objeto con una relación ForeignKey con otro obtiene esto gratuitamente. Cuando haga clic en "Agregar otra pregunta", obtendrá una ventana emergente con el formulario "Agregar pregunta". Si agrega una pregunta en esa ventana y hace clic en "Guardar", Django guardará la pregunta en la base de datos y la agregará dinámicamente como la opción seleccionada en el formulario "Agregar opción" que está viendo.

Pero, en realidad, esta es una manera ineficiente de agregar objetos Choice al sistema. Sería mejor si pudiera agregar un montón de Opciones directamente cuando crea el objeto Question. Hagamos que eso suceda.

Quite la llamada register() para el modelo Choice. Luego, edite el código de registro de Question para que se lea:

from django.contrib import admin

from.models import Choice, Question


class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["question_text"]}),
        ("Información de fecha", {"fields": ["pub_date"], "classes": ["collapse"]}),
    ]
    inlines = [ChoiceInline]


admin.site.register(Question, QuestionAdmin)

Esto le dice a Django: "Los objetos Choice se editan en la página de administración de Question. Por defecto, proporcione suficientes campos para 3 opciones".

Cargue la página "Agregar pregunta" para ver cómo se ve:

Question admin with choices

Funciona así: Hay tres espacios para Opciones relacionadas, como se especifica por extra, y cada vez que regrese a la página "Cambiar" para un objeto ya creado, obtendrá otros tres espacios adicionales.

Al final de los tres espacios actuales encontrará un enlace "Agregar otra Opción". Si hace clic en él, se agregará un nuevo espacio. Si desea eliminar el espacio agregado, puede hacer clic en la X en la esquina superior derecha del espacio agregado. Esta imagen muestra un espacio agregado:

Additional slot added dynamically

Sin embargo, un pequeño problema. Se necesita mucho espacio en pantalla para mostrar todos los campos para ingresar objetos Choice relacionados. Por esa razón, Django ofrece una manera tabular de mostrar objetos relacionados en línea. Para usarlo, cambie la declaración ChoiceInline para que se lea:

class ChoiceInline(admin.TabularInline):
 ...

Con ese TabularInline (en lugar de StackedInline), los objetos relacionados se muestran en un formato más compacto, basado en tablas:

Tabular inline choices display

Tenga en cuenta que hay una columna adicional "¿Eliminar?" que permite eliminar las filas agregadas usando el botón "Agregar otra Opción" y las filas que ya se han guardado.

Personalizar la lista de cambios del administrador

Ahora que la página de administración de Preguntas se ve bien, hagamos algunos ajustes en la página de "lista de cambios", la que muestra todas las preguntas en el sistema.

Así se ve en este momento:

Polls change list page

Por defecto, Django muestra la str() de cada objeto. Pero a veces sería más útil si pudiéramos mostrar campos individuales. Para hacer eso, use la opción de administración ~django.contrib.admin.ModelAdmin.list_display, que es una tupla de nombres de campos a mostrar, como columnas, en la página de lista de cambios del objeto:

class QuestionAdmin(admin.ModelAdmin):
    #...
    list_display = ["question_text", "pub_date"]

Para estar seguros, también incluyamos el método was_published_recently() de **Configurar la base de datos**:

class QuestionAdmin(admin.ModelAdmin):
    #...
    list_display = ["question_text", "pub_date", "was_published_recently"]

Ahora la página de lista de cambios de preguntas se ve así:

Question change list view

Puede hacer clic en los encabezados de columna para ordenar por esos valores, excepto en el caso del encabezado was_published_recently, porque no se admite ordenar por la salida de un método arbitrario. También observe que el encabezado de columna de was_published_recently es, por defecto, el nombre del método (con los guiones bajos reemplazados por espacios), y que cada línea contiene la representación de cadena de la salida.

Puede mejorarlo usando el decorador ~django.contrib.admin.display en ese método (en polls/models.py), como sigue:

from django.contrib import admin


class Question(models.Model):
    #...
    @admin.display(
        boolean=True,
        ordering="pub_date",
        description="¿Publicado recientemente?",
    )
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

Para obtener más información sobre las propiedades configurables a través del decorador, consulte ~django.contrib.admin.ModelAdmin.list_display.

Edite nuevamente su archivo polls/admin.py y agregue una mejora a la página de lista de cambios de Question: filtros usando ~django.contrib.admin.ModelAdmin.list_filter. Agregue la siguiente línea a QuestionAdmin:

list_filter = ["pub_date"]

Eso agrega una barra lateral de "Filtros" que permite a las personas filtrar la lista de cambios por el campo pub_date:

Admin list filter sidebar

El tipo de filtro que se muestra depende del tipo de campo en el que se está filtrando. Debido a que pub_date es un ~django.db.models.DateTimeField, Django sabe dar opciones de filtro adecuadas: "Cualquier fecha", "Hoy", "Últimos 7 días", "Este mes", "Este año".

Esto está quedando muy bien. Agreguemos alguna capacidad de búsqueda:

search_fields = ["question_text"]

Eso agrega una caja de búsqueda en la parte superior de la lista de cambios. Cuando alguien ingresa términos de búsqueda, Django buscará en el campo question_text. Puede usar tantos campos como desee, aunque como utiliza una consulta LIKE en segundo plano, limitar el número de campos de búsqueda a un número razonable hará que sea más fácil para su base de datos realizar la búsqueda.

Ahora también es un buen momento para señalar que las listas de cambios le dan paginación gratuita. El predeterminado es mostrar 100 elementos por página. Paginación de la lista de cambios <django.contrib.admin.ModelAdmin.list_per_page>, cajas de búsqueda <django.contrib.admin.ModelAdmin.search_fields>, filtros <django.contrib.admin.ModelAdmin.list_filter>, jerarquías de fechas <django.contrib.admin.ModelAdmin.date_hierarchy> y ordenamiento de encabezados de columna <django.contrib.admin.ModelAdmin.list_display> todos funcionan juntos como usted esperaría que lo hicieran.

Personalizar la apariencia y sensación del administrador

Obviamente, tener "Administración de Django" en la parte superior de cada página de administración es ridículo. Es solo texto de marcador de posición.

Sin embargo, puede cambiarlo usando el sistema de plantillas de Django. La interfaz de administración de Django está impulsada por Django mismo, y sus interfaces utilizan el propio sistema de plantillas de Django.

Personalizando las plantillas de su proyecto

Cree un directorio templates en el directorio de su proyecto (el que contiene manage.py). Las plantillas pueden estar en cualquier lugar del sistema de archivos que Django pueda acceder. (Django se ejecuta como el usuario que ejecute su servidor.) Sin embargo, mantener sus plantillas dentro del proyecto es una buena convención que seguir.

Abra su archivo de configuración (mysite/settings.py, recuerde) y agregue una opción DIRS <TEMPLATES-DIRS> en la configuración TEMPLATES:

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [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",
            ],
        },
    },
]

DIRS <TEMPLATES-DIRS> es una lista de directorios del sistema de archivos para verificar cuando se cargan las plantillas de Django; es una ruta de búsqueda.

Organizando las plantillas

Al igual que los archivos estáticos, podríamos tener todas nuestras plantillas juntas, en un gran directorio de plantillas, y funcionaría perfectamente. Sin embargo, las plantillas que pertenecen a una aplicación en particular deben ubicarse en el directorio de plantillas de esa aplicación (por ejemplo, polls/templates) en lugar del del proyecto (templates). Vamos a discutir en más detalle en el tutorial de aplicaciones reutilizables </intro/reusable-apps> por qué hacemos esto.

Ahora cree un directorio llamado admin dentro de templates, y copie la plantilla admin/base_site.html desde dentro del directorio de plantillas de administración predeterminado de Django en el código fuente de Django mismo (django/contrib/admin/templates) en ese directorio.

¿Dónde están los archivos fuente de Django?

Si tiene dificultades para encontrar donde se encuentran los archivos fuente de Django en su sistema, ejecute el siguiente comando:

python -c "import django; print(django.__path__)"
['/home/labex/.local/lib/python3.10/site-packages/django']

Luego, edite el archivo y reemplace {{ site_header|default:_('Django administration') }} (incluyendo las llaves) con el nombre de su propio sitio según le parezca adecuado. Debería terminar con una sección de código como:

{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">Administración de Encuestas</a><div>
{% endblock %}

Usamos este enfoque para enseñarle cómo sobrescribir plantillas. En un proyecto real, probablemente usaría el atributo django.contrib.admin.AdminSite.site_header para hacer esta personalización en particular de manera más fácil.

Este archivo de plantilla contiene mucho texto como {% block branding %} y {{ title }}. Las etiquetas {% y {{ son parte del lenguaje de plantillas de Django. Cuando Django renderiza admin/base_site.html, este lenguaje de plantillas se evaluará para producir la página HTML final, al igual que vimos en **Creando las vistas de la interfaz pública**.

Tenga en cuenta que cualquiera de las plantillas de administración predeterminadas de Django se puede sobrescribir. Para sobrescribir una plantilla, haga lo mismo que hizo con base_site.html: cópiela del directorio predeterminado en su directorio personalizado y haga los cambios.

Personalizando las plantillas de su aplicación

Los lectores perspicaces se preguntarán: Pero si DIRS <TEMPLATES-DIRS> estaba vacío por defecto, ¿cómo estaba Django encontrando las plantillas de administración predeterminadas? La respuesta es que, dado que APP_DIRS <TEMPLATES-APP_DIRS> está establecido en True, Django busca automáticamente un subdirectorio templates/ dentro de cada paquete de aplicación, para usarlo como alternativa (no olvide que django.contrib.admin es una aplicación).

Nuestra aplicación de encuestas no es muy compleja y no necesita plantillas de administración personalizadas. Pero si se volviera más sofisticada y requiriera la modificación de las plantillas de administración estándar de Django para alguna de sus funcionalidades, sería más sensato modificar las plantillas de la aplicación, en lugar de las del proyecto. De esa manera, podría incluir la aplicación de encuestas en cualquier nuevo proyecto y estar seguro de que encontraría las plantillas personalizadas que necesitaba.

Consulte la documentación de carga de plantillas <template-loading> para obtener más información sobre cómo Django encuentra sus plantillas.

Personalizar la página de índice del administrador

En un tono similar, es posible que desee personalizar la apariencia y sensación de la página de índice del administrador de Django.

Por defecto, muestra todas las aplicaciones en INSTALLED_APPS que se han registrado con la aplicación de administración, en orden alfabético. Es posible que desee realizar cambios significativos en el diseño. Después de todo, el índice es probablemente la página más importante del administrador y debe ser fácil de usar.

La plantilla para personalizar es admin/index.html. (Haga lo mismo que con admin/base_site.html en la sección anterior: cópiela del directorio predeterminado a su directorio de plantillas personalizadas). Edite el archivo y verá que utiliza una variable de plantilla llamada app_list. Esa variable contiene cada aplicación de Django instalada. En lugar de utilizar eso, puede codificar en duro enlaces a las páginas de administración específicas de objetos de la manera que crea más adecuada.

Resumen

¡Felicidades! Has completado el laboratorio de Personalización del Sitio de Administración de Django. Puedes practicar más laboratorios en LabEx para mejorar tus habilidades.