# documentación de Django - 1.10.7

# Escribiendo su primera aplicación Djando, parte 7

This tutorial begins where Tutorial 6 left off. We’re continuing the Web-poll application and will focus on customizing Django’s automatically-generated admin site that we first explored in Tutorial 2.

## Personalice el formulario del sitio administrativo

Al registrar el modelo `Question` con admin.site.register (Question)`, Django pudo construir una representación del formulario predeterminado. A menudo, usted querrá personalizar el aspecto y el funcionamiento del formulario del sitio administrativo. Usted hará esto indicándole a Django las opciones que desee cuando registre el objeto.

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

polls/admin.py

    from django.contrib import admin

    from .models import Question

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

    admin.site.register(Question, QuestionAdmin)

You’ll follow this pattern – create a model admin class, then pass it as the second argument to `admin.site.register()` – any time you need to change the admin options for a model.

Esta modificación concreta citada anteriormente hace que la “Publication date” se anteponga al campo “Question”:

Esto no es tan impresionante con sólo dos campos, pero para los formularios del sitio administrativo con docenas de campos, elegir un orden intuitivo es un detalle importante de usabilidad.

y hablando de formularios con docenas de campos, es posible que desee dividir el formulario en grupos de campos:

polls/admin.py

    from django.contrib import admin

    from .models import Question

    class QuestionAdmin(admin.ModelAdmin):
        fieldsets = [
            (None,               {'fields': ['question_text']}),
            ('Date information', {'fields': ['pub_date']}),
        ]

    admin.site.register(Question, QuestionAdmin)

El primer elemento de cada tupla en `fieldsets` es el título del grupo de campos. Así es como se ve el formulario ahora:

## Agregando objetos relacionados

OK, tenemos nuestra página de administración Question, pero una `Question` tiene varias `` Choice``s, y la página de administración no muestra opciones.

Sin embargo,

Hay dos formas de resolver este problema. La primera es registrar `Choice` con el sitio administrativo tal como lo hicimos con `Question`. Eso es fácil:

polls/admin.py

    from django.contrib import admin

    from .models import Choice, Question
    # ...
    admin.site.register(Choice)

Ahora “Choices” es una opción disponible en el sitio administrativo de Django. El formulario “Add choice” se ve así:

En ese formulario, el campo “Question” es un cuadro de selección que contiene cada pregunta de la base de datos. Django sabe que una `ForeignKey` debería estar representada en el sitio administrativo como un cuadro `` <select>``. En nuestro caso, solo existe una pregunta en este momento.

También tenga en cuenta el enlace “Add another” que está al lado de “Question”. Cada objeto que tiene una relación `ForeignKey` con otro obtiene este libremente . Al hacer clic en “Add another”, aparecerá una ventana emergente con el formulario “Add question”. Si usted agrega una pregunta en esa ventana y hace clic en “Save”, Django guardará la pregunta en la base de datos y la agregará dinámicamente como la opción seleccionada en el formulario “Add choice” que usted está mirando.

Pero, en realidad, se trata de una forma ineficiente de añadir objetos `Choice` al sistema. Sería mejor si usted pudiese agregar muchas Choices directamente cuando crea el objeto `Question`. Hagámoslo realidad.

Elimine la llamada `register()` para el modelo `Choice`. Después, edite el código de registro de “Question” para que diga:

polls/admin.py

    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']}),
            ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
        ]
        inlines = [ChoiceInline]

    admin.site.register(Question, QuestionAdmin)

Esto le indica a Django: “Los objetos `Choice` se editan en la página de administración `Question`. De forma predeterminada, proporciona suficientes campos para 3 opciones.”.

Cargue la página “Add question” para ver cómo se ve:

Funciona así: Hay tres espacios para las opciones relacionadas, como indica `extra`, y cada vez que usted vuelva a la página “change” para un objeto ya creado, usted obtiene otros tres espacios adicionales.

Al final de los tres espacios actuales se encuentra un enlace “Add another choice”. Si hace clic en él, se añadirá un espacio nuevo. Si desea eliminar el espacio adicional, usted puede hacer clic en la X en la parte superior derecha del espacio añadido. Tenga en cuenta que no puede eliminar los tres espacios originales. Esta imagen muestra un espacio añadido:

Sin embargo, hay un pequeño problema. Se necesita una gran cantidad de espacio en la pantalla para visualizar todos los campos para introducir los objetos `Choices` relacionados. Por esa razón, Django ofrece una forma tabular de mostrar los objetos relacionados en línea; usted sólo tiene que cambiar la declaración `ChoiceInline` para que diga:

polls/admin.py

    class ChoiceInline(admin.TabularInline):
        #...

Los objetos relacionados se muestran en un formato más compacto basado en tablas con esa `TabularInline` (en lugar de `StackedInline`):

Tenga en cuenta que hay una columna “Delete?” extra que permite la eliminación de filas añadidas utilizando el botón “Add Another Choice” y las filas que ya han sido guardadas.

## Personalice la lista de cambios del sitio administrativo

Ahora que la página de administración Question se ve bien, vamos a hacer algunos ajustes a la página “change list”, la que muestra todas las preguntas en el sistema.

Así es como se ve en este momento:

Por defecto, Django muestra el `str()` de cada objeto, pero a veces sería más útil si pudiéramos mostrar los campos individuales. Para hacerlo, utilice la opción del sitio administrativo: attr:~ django.contrib.admin.ModelAdmin.list_display, que es una tupla de nombres de campos para que se muestre como columnas en la página de lista de cambios para el objeto:

polls/admin.py

    class QuestionAdmin(admin.ModelAdmin):
        # ...
        list_display = ('question_text', 'pub_date')

Sólo por si acaso, también vamos a incluir el método `was_published_recently ()` del :doc: Tutorial 2 </intro/tutorial02>:

polls/admin.py

    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í:

Usted puede hacer clic en las cabeceras de las columnas para ordenar por esos valores ,excepto en el caso de la cabecera `was_published_recently`, porque ordenar por la salida de un método arbitrario no está soportado. También tenga en cuenta que la cabecera de la columna `` was_published_recently`` es, por defecto, el nombre del método (con guiones bajos reemplazado con espacios), y que cada línea contiene la representación de cadena de la salida.

Usted puede mejorar eso al darle a ese método (en `polls/models.py`) algunos atributos, de la siguiente manera:

polls/models.py

    class Question(models.Model):
        # ...
        def was_published_recently(self):
            now = timezone.now()
            return now - datetime.timedelta(days=1) <= self.pub_date <= now
        was_published_recently.admin_order_field = 'pub_date'
        was_published_recently.boolean = True
        was_published_recently.short_description = 'Published recently?'

Para obtener más información sobre estas propiedades del método, consulte `list_display`.

Edite de nuevo su archivo `polls/admin.py` y añada una mejora a la página de la lista de cambios `Question`: filtre utilizando el :attr: ~django.contrib.admin.ModelAdmin.list_filter. Agregue la siguiente línea a `` QuestionAdmin``:

    list_filter = ['pub_date']

Eso añade una barra lateral “Filter” que le permite a los usuarios filtrar la lista de cambios mediante el campo `pub_date`:

El tipo de filtro que se muestra depende del tipo de campo que está filtrando. Debido a que la `pub_date` es una `DateTimeField`, Django sabe dar opciones de filtro apropiadas: “Any date”, “Today”, “Past 7 days”, “This month”, “This year”.

Esto se perfila bien. Vamos a añadir un poco de capacidad de búsqueda:

    search_fields = ['question_text']

Eso añade un cuadro de búsqueda en la parte superior de la lista de cambios. Cuando alguien introduce los términos de búsqueda, Django buscará el campo `question_text`. Usted puede utilizar tantos campos como desee, sin embargo, ya que utiliza una petición `LIKE` detrás de bastidores, limitar el número de campos de búsqueda a un número razonable le facilitará la búsqueda a su base de datos.

Now’s also a good time to note that change lists give you free pagination. The default is to display 100 items per page. `Change list pagination`, `search boxes`, `filters`, `date-hierarchies`, and `column-header-ordering` all work together like you think they should.

## Personalice el aspecto del sitio administrativo

Está claro que tener “Django administration” en la parte superior de cada página del sitio administrativo es ridículo. Es sólo texto del marcador de posición.

Sin embargo, eso es fácil de cambiar, utilizando el sistema de plantillas de Django. El sitio administrativo de Django es impulsado por Django mismo y sus interfaces utilizan el 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 se pueden ubicar en cualquier parte de su sistema de archivos al que Django pueda acceder. (Django ejecuta como cualquier usuario ejecuta su servidor.) Sin embargo, una buena práctica a seguir es guardar sus plantillas en el proyecto.

Abra el archivo de configuraciónes (`mysite/settings.py`, recuerde) y añada una opción `DIRS` en la opción `TEMPLATES`:

mysite/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',
                ],
            },
        },
    ]

`DIRS` es una lista de directorios del sistema de archivos utilizada para comprobar cuando se cargan las plantillas de Django; es una ruta de búsqueda.

Organizando las plantillas

Just like the static files, we could have all our templates together, in one big templates directory, and it would work perfectly well. However, templates that belong to a particular application should be placed in that application’s template directory (e.g. `polls/templates`) rather than the project’s (`templates`). We’ll discuss in more detail in the reusable apps tutorial why we do this.

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

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

Si tiene dificultad para encontrar donde están localizados los archivos fuente de Django en su sistema, ejecute el siguiente comando:

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

Luego, solo edite el archivo y reemplace `{{site_header|default: _ ('Django administración') }}` (incluyendo las llaves) con el nombre de su propio sitio como mejor le parezca. Usted debe terminar con una sección de código como:

    {% block branding %}
    <h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
    {% endblock %}

Utilizamos este método para enseñarle cómo reemplazar las plantillas. En un proyecto real, usted probablemente utilizaría el atributo `django.contrib.admin.AdminSite.site_header` para hacer este ajuste particular con mayor facilidad.

Este archivo de plantillas contiene una gran cantidad de texto como `{% block branding%} `` y ``{{title}}`. Las etiquetas `{%` y `{{` son parte del lenguaje de plantillas de Django. Cuando Django crea `admin/base_site.html`, este lenguaje de plantilla será evaluado para generar la página HTML definitiva, como vimos en el Tutorial 3.

Tenga en cuenta que cualquier plantilla predeterminada del sitio administrativo de Django se puede modificar. Para modificar una plantilla, simplemente haga lo mismo que hizo con `base_site.html`: cópiela desde el directorio predeterminado en el directorio personalizado y realice los cambios.

### Personalizando las plantillas de su aplicación

Los lectores agudos preguntarán: ¿Pero si `DIRS <TEMPLATES-DIRS> ` estaba vacío por defecto, ¿Cómo Django estaba buscando las plantillas del sitio administrativo predeterminado? La respuesta es que, ya que :setting:`APP_DIRS <TEMPLATES-APP_DIRS` está fijado como `True`, Django busca automáticamente un subdirectorio `templates /` dentro de cada paquete de la aplicación, para su uso como una solución alternativa (no olvide que `django.contrib.admin` es una aplicación).

Nuestra aplicación encuestas no es muy compleja y no necesita las plantillas personalizadas del sitio administrativo. Pero si se hiciera más sofisticada y requiriera la modificación de las plantillas convencionales del sitio administrativo de Django para algunas de sus funciones, sería más sensato modificar las plantillas de la aplicación, en lugar de las que están en el proyecto. De esa manera, usted podría incluir la aplicación encuestas en cualquier nuevo proyecto y estaría seguro de que esta encontraría las plantillas personalizadas que necesitaba.

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

## Personalice la página del índice del sitio administrativo.

En este sentido, es posible que desee personalizar la apariencia de la página de índice del sitio administrativo de Django.

Por defecto, muestra todas las aplicaciones que se encuentran en :setting: INSTALLED_APPS que han sido registradas en la aplicación del sitio administrativo 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 sitio administrativo y debería ser fácil de usar.

La plantilla a personalizar es `admin/index.html`. (Haga lo mismo que hizo con `admin/ base_site.html` en la sección anterior: cópiela desde el directorio predeterminado en el directorio de plantillas personalizadas). Edite el archivo y verá que utiliza una variable de plantilla llamada `app_list`. Esa variable contiene todas las aplicaciones instaladas de Django. En lugar de utilizar esa, usted puede predeterminar enlaces a páginas del sitio administrativo específicas de objeto de la manera que le parezca mejor.

## ¿Qué sigue?

El tutorial para principiantes finaliza aquí. Mientras tanto, es posible que desee ver algunos consejos sobre a dónde ir a partir de ahora.

Si está familiarizado con el empaquetado Python e interesado en aprender cómo convertir la aplicación encuestas en una “aplicación reutilizable”, consulte el tutorial avanzado: Cómo escribir aplicaciones reutilizables.