{"title":"Escribiendo su primera aplicación Django, parte 7","version":"3.1","locale":"es","docname":"intro/tutorial07","url":"/es/3.1/intro/tutorial07/","canonical":"https://djangodocs.dev/es/3.1/intro/tutorial07/","summary":"Este tutorial comienza donde quedó el Tutorial 6 . Continúamos con la aplicación Web encuestas y nos vamos a enfocar en personalizar el sitio administrativo de…","html":"<h1>Escribiendo su primera aplicación Django, parte 7<a class=\"heading-anchor\" href=\"#writing-your-first-django-app-part-7\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Este tutorial comienza donde quedó el <a class=\"reference internal\" href=\"/es/3.1/intro/tutorial06/\"><span class=\"doc\">Tutorial 6</span></a>. Continúamos con la aplicación Web encuestas y nos vamos a enfocar en personalizar el sitio administrativo de Django generado automáticamente que estudiamos primero en el <a class=\"reference internal\" href=\"/es/3.1/intro/tutorial02/\"><span class=\"doc\">Tutorial 2</span></a>.</p>\n<aside class=\"admonition-where-to-get-help admonition\">\n<p class=\"admonition-title\">Dónde obtener ayuda:</p>\n<p>If you’re having trouble going through this tutorial, please head over to\nthe <a class=\"reference internal\" href=\"/es/3.1/faq/help/\"><span class=\"doc\">Getting Help</span></a> section of the FAQ.</p>\n</aside>\n<section id=\"customize-the-admin-form\">\n<h2>Personalice el formulario del sitio administrativo<a class=\"heading-anchor\" href=\"#customize-the-admin-form\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Al registrar el modelo <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> 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.</p>\n<p>Veamos cómo funciona esto reordenando los campos en el formulario de edición. Reemplace la línea <code class=\"docutils literal notranslate\"><span class=\"pre\">admin.site.register(Question)</span></code> con:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/admin.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Question</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QuestionAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">fields</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;question_text&#39;</span><span class=\"p\">]</span>\n\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">QuestionAdmin</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>Usted seguirá este patrón - cree una clase de modelo del sitio administrativo y luego pásela como el segundo argumento a <code class=\"docutils literal notranslate\"><span class=\"pre\">admin.site.register()</span></code> - cada vez que necesite cambiar las opciones del sitio administrativo para un modelo.</p>\n<p>Esta modificación concreta citada anteriormente hace que la «Publication date» se anteponga al campo «Question»:</p>\n<img alt=\"Fields have been reordered\" src=\"/es/3.1/_images/admin07.png\" />\n<p>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.</p>\n<p>Y hablando de formularios con docenas de campos, es posible que desee dividir el formulario en grupos de campos:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/admin.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Question</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QuestionAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">fieldsets</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span>               <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;question_text&#39;</span><span class=\"p\">]}),</span>\n        <span class=\"p\">(</span><span class=\"s1\">&#39;Date information&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">]}),</span>\n    <span class=\"p\">]</span>\n\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">QuestionAdmin</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>El primer elemento de cada tupla en <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets\" title=\"django.contrib.admin.ModelAdmin.fieldsets\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">fieldsets</span></code></a> es el título del grupo de campos. Así es como se ve el formulario ahora:</p>\n<img alt=\"Form has fieldsets now\" src=\"/es/3.1/_images/admin08t.png\" />\n</section>\n<section id=\"adding-related-objects\">\n<h2>Agregando objetos relacionados<a class=\"heading-anchor\" href=\"#adding-related-objects\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>OK, tenemos nuestra página de administración Question, pero una <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> tiene varias <code class=\"docutils literal notranslate\"><span class=\"pre\">Choice</span></code>s, y la página de administración no muestra opciones.</p>\n<p>Sin embargo.</p>\n<p>There are two ways to solve this problem. The first is to register <code class=\"docutils literal notranslate\"><span class=\"pre\">Choice</span></code>\nwith the admin just as we did with <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/admin.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Choice</span><span class=\"p\">,</span> <span class=\"n\">Question</span>\n<span class=\"c1\"># ...</span>\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">Choice</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>Ahora «Choices» es una opción disponible en el sitio administrativo de Django. El formulario «Add choice» se ve así:</p>\n<img alt=\"Choice admin page\" src=\"/es/3.1/_images/admin09.png\" />\n<p>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 <a class=\"reference internal\" href=\"/es/3.1/ref/models/fields/#django.db.models.ForeignKey\" title=\"django.db.models.ForeignKey\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code></a> debería estar representada en el sitio administrativo como un cuadro <code class=\"docutils literal notranslate\"><span class=\"pre\">&lt;select&gt;</span></code>. En nuestro caso, solo existe una pregunta en este momento.</p>\n<p>También tenga en cuenta el enlace «Add another» que está al lado de «Question». Cada objeto que tiene una relación <code class=\"docutils literal notranslate\"><span class=\"pre\">ForeignKey</span></code> 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.</p>\n<p>Pero, en realidad, se trata de una forma ineficiente de añadir objetos <code class=\"docutils literal notranslate\"><span class=\"pre\">Choice</span></code> al sistema. Sería mejor si usted pudiese agregar muchas Choices directamente cuando crea el objeto <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>. Hagámoslo realidad.</p>\n<p>Elimine la llamada <code class=\"docutils literal notranslate\"><span class=\"pre\">register()</span></code> para el modelo <code class=\"docutils literal notranslate\"><span class=\"pre\">Choice</span></code>. Después, edite el código de registro de <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> para que diga:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/admin.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.contrib</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">admin</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Choice</span><span class=\"p\">,</span> <span class=\"n\">Question</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ChoiceInline</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">StackedInline</span><span class=\"p\">):</span>\n    <span class=\"n\">model</span> <span class=\"o\">=</span> <span class=\"n\">Choice</span>\n    <span class=\"n\">extra</span> <span class=\"o\">=</span> <span class=\"mi\">3</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QuestionAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"n\">fieldsets</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n        <span class=\"p\">(</span><span class=\"kc\">None</span><span class=\"p\">,</span>               <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;question_text&#39;</span><span class=\"p\">]}),</span>\n        <span class=\"p\">(</span><span class=\"s1\">&#39;Date information&#39;</span><span class=\"p\">,</span> <span class=\"p\">{</span><span class=\"s1\">&#39;fields&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">],</span> <span class=\"s1\">&#39;classes&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"s1\">&#39;collapse&#39;</span><span class=\"p\">]}),</span>\n    <span class=\"p\">]</span>\n    <span class=\"n\">inlines</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"n\">ChoiceInline</span><span class=\"p\">]</span>\n\n<span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">site</span><span class=\"o\">.</span><span class=\"n\">register</span><span class=\"p\">(</span><span class=\"n\">Question</span><span class=\"p\">,</span> <span class=\"n\">QuestionAdmin</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>Esto le indica a Django: «Los objetos <code class=\"docutils literal notranslate\"><span class=\"pre\">Choice</span></code> se editan en la página de administración <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>. De forma predeterminada, proporciona suficientes campos para 3 opciones.»</p>\n<p>Cargue la página «Add question» para ver cómo se ve:</p>\n<img alt=\"Add question page now has choices on it\" src=\"/es/3.1/_images/admin10t.png\" />\n<p>Funciona así: Hay tres slots para las opciones relacionadas – como indica <code class=\"docutils literal notranslate\"><span class=\"pre\">extra</span></code> – y cada vez que usted vuelva a la página «Change» para un objeto ya creado, usted obtiene otros tres espacios adicionales.</p>\n<p>At the end of the three current slots you will find an «Add another Choice»\nlink.  If you click on it, a new slot will be added. If you want to remove the\nadded slot, you can click on the X to the top right of the added slot. This\nimage shows an added slot:</p>\n<img alt=\"Additional slot added dynamically\" src=\"/es/3.1/_images/admin14t.png\" />\n<p>One small problem, though. It takes a lot of screen space to display all the\nfields for entering related <code class=\"docutils literal notranslate\"><span class=\"pre\">Choice</span></code> objects. For that reason, Django offers a\ntabular way of displaying inline related objects. To use it, change the\n<code class=\"docutils literal notranslate\"><span class=\"pre\">ChoiceInline</span></code> declaration to read:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/admin.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">ChoiceInline</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">TabularInline</span><span class=\"p\">):</span>\n    <span class=\"c1\">#...</span>\n</code></pre></figure>\n<p>Los objetos relacionados se muestran en un formato más compacto basado en tablas con esa <code class=\"docutils literal notranslate\"><span class=\"pre\">TabularInline</span></code> (en lugar de <code class=\"docutils literal notranslate\"><span class=\"pre\">StackedInline</span></code>):</p>\n<img alt=\"Add question page now has more compact choices\" src=\"/es/3.1/_images/admin11t.png\" />\n<p>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.</p>\n</section>\n<section id=\"customize-the-admin-change-list\">\n<h2>Personalice la lista de cambios del sitio administrativo<a class=\"heading-anchor\" href=\"#customize-the-admin-change-list\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>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.</p>\n<p>Así es como se ve en este momento:</p>\n<img alt=\"Polls change list page\" src=\"/es/3.1/_images/admin04t.png\" />\n<p>Por defecto, Django muestra el <code class=\"docutils literal notranslate\"><span class=\"pre\">str()</span></code> 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:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/admin.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QuestionAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ...</span>\n    <span class=\"n\">list_display</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;question_text&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>For good measure, let’s also include the <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code> method\nfrom <a class=\"reference internal\" href=\"/es/3.1/intro/tutorial02/\"><span class=\"doc\">Tutorial 2</span></a>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/admin.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QuestionAdmin</span><span class=\"p\">(</span><span class=\"n\">admin</span><span class=\"o\">.</span><span class=\"n\">ModelAdmin</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ...</span>\n    <span class=\"n\">list_display</span> <span class=\"o\">=</span> <span class=\"p\">(</span><span class=\"s1\">&#39;question_text&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;was_published_recently&#39;</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>Ahora la página de lista de cambios de preguntas se ve así:</p>\n<img alt=\"Polls change list page, updated\" src=\"/es/3.1/_images/admin12t.png\" />\n<p>Usted puede hacer clic en las cabeceras de las columnas para ordenar por esos valores ,excepto en el caso de la cabecera <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently</span></code>, porque ordenar por la salida de un método arbitrario no está soportado. También tenga en cuenta que la cabecera de la columna <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently</span></code> 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.</p>\n<p>Usted puede mejorar eso al darle a ese método (en el archivo <code class=\"file docutils literal notranslate\"><span class=\"pre\">polls/models.py</span></code>) algunos atributos, de la siguiente manera:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/models.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">Question</span><span class=\"p\">(</span><span class=\"n\">models</span><span class=\"o\">.</span><span class=\"n\">Model</span><span class=\"p\">):</span>\n    <span class=\"c1\"># ...</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">was_published_recently</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n        <span class=\"k\">return</span> <span class=\"n\">now</span> <span class=\"o\">-</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">&lt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pub_date</span> <span class=\"o\">&lt;=</span> <span class=\"n\">now</span>\n    <span class=\"n\">was_published_recently</span><span class=\"o\">.</span><span class=\"n\">admin_order_field</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;pub_date&#39;</span>\n    <span class=\"n\">was_published_recently</span><span class=\"o\">.</span><span class=\"n\">boolean</span> <span class=\"o\">=</span> <span class=\"kc\">True</span>\n    <span class=\"n\">was_published_recently</span><span class=\"o\">.</span><span class=\"n\">short_description</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;Published recently?&#39;</span>\n</code></pre></figure>\n<p>Para obtener más información sobre estas propiedades del método, consulte <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display\" title=\"django.contrib.admin.ModelAdmin.list_display\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">list_display</span></code></a>.</p>\n<p>Edite de nuevo su archivo <code class=\"file docutils literal notranslate\"><span class=\"pre\">polls/admin.py</span></code> y añada una mejora a la página <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> en la lista de cambios: filtre utilizando el <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter\" title=\"django.contrib.admin.ModelAdmin.list_filter\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">list_filter</span></code></a>. Agregue la siguiente línea a <code class=\"docutils literal notranslate\"><span class=\"pre\">QuestionAdmin</span></code>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">list_filter</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;pub_date&#39;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>Eso añade una barra lateral «Filter» que le permite a los usuarios filtrar la lista de cambios mediante el campo <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code>:</p>\n<img alt=\"Polls change list page, updated\" src=\"/es/3.1/_images/admin13t.png\" />\n<p>El tipo de filtro que se muestra depende del tipo de campo que está filtrando. Debido a que la <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> es una <a class=\"reference internal\" href=\"/es/3.1/ref/models/fields/#django.db.models.DateTimeField\" title=\"django.db.models.DateTimeField\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">DateTimeField</span></code></a>, Django sabe dar opciones de filtro apropiadas: «Any date», «Today», «Past 7 days», «This month», «This year».</p>\n<p>Esto se perfila bien. Vamos a añadir un poco de capacidad de búsqueda:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">search_fields</span> <span class=\"o\">=</span> <span class=\"p\">[</span><span class=\"s1\">&#39;question_text&#39;</span><span class=\"p\">]</span>\n</code></pre></div>\n<p>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 <code class=\"docutils literal notranslate\"><span class=\"pre\">question_text</span></code>. Usted puede utilizar tantos campos como desee, sin embargo, ya que utiliza una petición <code class=\"docutils literal notranslate\"><span class=\"pre\">LIKE</span></code> 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.</p>\n<p>Ahora también es un buen momento para señalar que las listas de cambios le dan paginación libre. El modo predeterminado muestra 100 items por página. <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_per_page\" title=\"django.contrib.admin.ModelAdmin.list_per_page\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">Paginación</span> <span class=\"pre\">de</span> <span class=\"pre\">la</span> <span class=\"pre\">lista</span> <span class=\"pre\">de</span> <span class=\"pre\">cambios</span></code></a>, <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields\" title=\"django.contrib.admin.ModelAdmin.search_fields\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">cuadros</span> <span class=\"pre\">de</span> <span class=\"pre\">búsqueda</span></code></a>, <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter\" title=\"django.contrib.admin.ModelAdmin.list_filter\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">:attr:`filtros</span></code></a>, <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.date_hierarchy\" title=\"django.contrib.admin.ModelAdmin.date_hierarchy\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">jerarquías</span> <span class=\"pre\">de</span> <span class=\"pre\">fecha</span></code></a> y <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display\" title=\"django.contrib.admin.ModelAdmin.list_display\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">orden</span> <span class=\"pre\">de</span> <span class=\"pre\">la</span> <span class=\"pre\">cabecera</span> <span class=\"pre\">de</span> <span class=\"pre\">columnas</span></code></a> todos trabajan juntos como usted piensa que deberían.</p>\n</section>\n<section id=\"customize-the-admin-look-and-feel\">\n<h2>Personalice el aspecto del sitio administrativo<a class=\"heading-anchor\" href=\"#customize-the-admin-look-and-feel\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>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.</p>\n<p>You can change it, though, using Django’s template system. The Django admin is\npowered by Django itself, and its interfaces use Django’s own template system.</p>\n<section id=\"customizing-your-project-s-templates\">\n<span id=\"ref-customizing-your-projects-templates\"></span><h3>Personalizando las plantillas de su <em>proyecto</em><a class=\"heading-anchor\" href=\"#customizing-your-project-s-templates\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Cree un directorio <code class=\"docutils literal notranslate\"><span class=\"pre\">templates</span></code> en el directorio de su proyecto (el que contiene <code class=\"docutils literal notranslate\"><span class=\"pre\">manage.py</span></code>). 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.</p>\n<p>Abra el archivo de configuraciones (<code class=\"file docutils literal notranslate\"><span class=\"pre\">mysite/settings.py</span></code>, recuerde) y añada una opción <a class=\"reference internal\" href=\"/es/3.1/ref/settings/#std-setting-TEMPLATES-DIRS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">DIRS</span></code></a> en la opción <a class=\"reference internal\" href=\"/es/3.1/ref/settings/#std-setting-TEMPLATES\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">TEMPLATES</span></code></a>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">mysite/settings.py</figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"n\">TEMPLATES</span> <span class=\"o\">=</span> <span class=\"p\">[</span>\n    <span class=\"p\">{</span>\n        <span class=\"s1\">&#39;BACKEND&#39;</span><span class=\"p\">:</span> <span class=\"s1\">&#39;django.template.backends.django.DjangoTemplates&#39;</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;DIRS&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span><span class=\"n\">BASE_DIR</span> <span class=\"o\">/</span> <span class=\"s1\">&#39;templates&#39;</span><span class=\"p\">],</span>\n        <span class=\"s1\">&#39;APP_DIRS&#39;</span><span class=\"p\">:</span> <span class=\"kc\">True</span><span class=\"p\">,</span>\n        <span class=\"s1\">&#39;OPTIONS&#39;</span><span class=\"p\">:</span> <span class=\"p\">{</span>\n            <span class=\"s1\">&#39;context_processors&#39;</span><span class=\"p\">:</span> <span class=\"p\">[</span>\n                <span class=\"s1\">&#39;django.template.context_processors.debug&#39;</span><span class=\"p\">,</span>\n                <span class=\"s1\">&#39;django.template.context_processors.request&#39;</span><span class=\"p\">,</span>\n                <span class=\"s1\">&#39;django.contrib.auth.context_processors.auth&#39;</span><span class=\"p\">,</span>\n                <span class=\"s1\">&#39;django.contrib.messages.context_processors.messages&#39;</span><span class=\"p\">,</span>\n            <span class=\"p\">],</span>\n        <span class=\"p\">},</span>\n    <span class=\"p\">},</span>\n<span class=\"p\">]</span>\n</code></pre></figure>\n<p><a class=\"reference internal\" href=\"/es/3.1/ref/settings/#std-setting-TEMPLATES-DIRS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">DIRS</span></code></a> 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.</p>\n<aside class=\"admonition-organizing-templates admonition\">\n<p class=\"admonition-title\">Organizando las plantillas</p>\n<p>Al igual que los archivos estáticos <em>podríamos</em> tener todas nuestras plantillas juntas en un gran directorio de plantillas y funcionaría perfectamente. Sin embargo, las plantillas que pertenecen a una determinada aplicación deberían ser puestas en el directorio de plantillas de la aplicación (por ejemplo, <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/templates</span></code>) en lugar del directorio (<code class=\"docutils literal notranslate\"><span class=\"pre\">templates</span></code>) del proyecto. Hablaremos con más detalle <em>por qué</em> hacemos esto en el <a class=\"reference internal\" href=\"/es/3.1/intro/reusable-apps/\"><span class=\"doc\">tutorial de aplicaciones reutilizables</span></a>.</p>\n</aside>\n<p>Ahora cree un directorio llamado <code class=\"docutils literal notranslate\"><span class=\"pre\">admin</span></code> dentro de <code class=\"docutils literal notranslate\"><span class=\"pre\">templates</span></code> y copie la plantilla <code class=\"docutils literal notranslate\"><span class=\"pre\">admin/base_site.html</span></code> desde dentro del directorio de plantillas predeterminado del sitio administrativo de Django en el código fuente de Django (<code class=\"docutils literal notranslate\"><span class=\"pre\">django/contrib/admin/templates</span></code>) en ese directorio.</p>\n<aside class=\"admonition-where-are-the-django-source-files admonition\">\n<p class=\"admonition-title\">¿Dónde están los archivos fuente de Django?</p>\n<p>Si tiene dificultad para encontrar donde están localizados los archivos fuente de Django en su sistema, ejecute el siguiente comando:</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-0-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Shell code\"><code><span class=\"gp\">$ </span>python<span class=\"w\"> </span>-c<span class=\"w\"> </span><span class=\"s2\">&quot;import django; print(django.__path__)&quot;</span>\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-0-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> py -c <span class=\"s2\">&quot;import django; print(django.__path__)&quot;</span>\n</code></pre></div></div></div>\n</aside>\n<p>Then, edit the file and replace\n<code class=\"docutils literal notranslate\"><span class=\"pre\">{{</span> <span class=\"pre\">site_header|default:_('Django</span> <span class=\"pre\">administration')</span> <span class=\"pre\">}}</span></code> (including the curly\nbraces) with your own site’s name as you see fit. You should end up with\na section of code like:</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">block</span> <span class=\"nv\">branding</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">h1</span> <span class=\"na\">id</span><span class=\"o\">=</span><span class=\"s\">&quot;site-name&quot;</span><span class=\"p\">&gt;&lt;</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{%</span> <span class=\"k\">url</span> <span class=\"s1\">&#39;admin:index&#39;</span> <span class=\"cp\">%}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>Polls Administration<span class=\"p\">&lt;/</span><span class=\"nt\">a</span><span class=\"p\">&gt;&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endblock</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<p>Utilizamos este método para enseñarle cómo reemplazar las plantillas. En un proyecto real, usted probablemente utilizaría el atributo <a class=\"reference internal\" href=\"/es/3.1/ref/contrib/admin/#django.contrib.admin.AdminSite.site_header\" title=\"django.contrib.admin.AdminSite.site_header\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">django.contrib.admin.AdminSite.site_header</span></code></a> para hacer este ajuste particular con mayor facilidad.</p>\n<p>Este archivo de plantillas contiene una gran cantidad de texto como <code class=\"docutils literal notranslate\"><span class=\"pre\">{%</span> <span class=\"pre\">block</span> <span class=\"pre\">branding%}</span></code> y <code class=\"docutils literal notranslate\"><span class=\"pre\">{{title}}</span></code>. Las etiquetas <code class=\"docutils literal notranslate\"><span class=\"pre\">{%</span></code> y <code class=\"docutils literal notranslate\"><span class=\"pre\">{{</span></code> son parte del lenguaje de plantillas de Django. Cuando Django crea <code class=\"docutils literal notranslate\"><span class=\"pre\">admin/base_site.html</span></code>, este lenguaje de plantilla será evaluado para generar la página HTML definitiva, como vimos en el <a class=\"reference internal\" href=\"/es/3.1/intro/tutorial03/\"><span class=\"doc\">Tutorial 3</span></a>.</p>\n<p>Note that any of Django’s default admin templates can be overridden. To\noverride a template, do the same thing you did with <code class=\"docutils literal notranslate\"><span class=\"pre\">base_site.html</span></code> – copy\nit from the default directory into your custom directory, and make changes.</p>\n</section>\n<section id=\"customizing-your-application-s-templates\">\n<h3>Personalizando las plantillas de su <em>aplicación</em><a class=\"heading-anchor\" href=\"#customizing-your-application-s-templates\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Los lectores agudos preguntarán: ¿Pero si <a class=\"reference internal\" href=\"/es/3.1/ref/settings/#std-setting-TEMPLATES-DIRS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">DIRS</span></code></a> estaba vacío por defecto, ¿Cómo Django estaba buscando las plantillas del sitio administrativo predeterminado? La respuesta es que, ya que <code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">APP_DIRS</span> <span class=\"pre\">&lt;TEMPLATES-APP_DIRS</span></code> está fijado como <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>, Django busca automáticamente un subdirectorio <code class=\"docutils literal notranslate\"><span class=\"pre\">templates/</span></code> dentro de cada paquete de la aplicación, para su uso como una solución alternativa (no olvide que <code class=\"docutils literal notranslate\"><span class=\"pre\">django.contrib.admin</span></code> es una aplicación).</p>\n<p>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 <em>aplicación</em>, en lugar de las que están en el <em>proyecto</em>. 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.</p>\n<p>Consulte la <a class=\"reference internal\" href=\"/es/3.1/topics/templates/#template-loading\"><span class=\"std std-ref\">documentación sobre la carga de plantillas</span></a> para obtener más información sobre cómo Django encuentra sus plantillas.</p>\n</section>\n</section>\n<section id=\"customize-the-admin-index-page\">\n<h2>Personalice la página del índice del sitio administrativo<a class=\"heading-anchor\" href=\"#customize-the-admin-index-page\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>En este sentido, es posible que desee personalizar la apariencia de la página de índice del sitio administrativo de Django.</p>\n<p>Por defecto, muestra todas las aplicaciones que se encuentran en <a class=\"reference internal\" href=\"/es/3.1/ref/settings/#std-setting-INSTALLED_APPS\"><code class=\"xref std std-setting docutils literal notranslate\"><span class=\"pre\">INSTALLED_APPS</span></code></a> 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.</p>\n<p>La plantilla a personalizar es <code class=\"docutils literal notranslate\"><span class=\"pre\">admin/index.html</span></code>. (Haga lo mismo que hizo con <code class=\"docutils literal notranslate\"><span class=\"pre\">admin/base_site.html</span></code> 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 <code class=\"docutils literal notranslate\"><span class=\"pre\">app_list</span></code>. 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.</p>\n</section>\n<section id=\"what-s-next\">\n<h2>¿Qué sigue?<a class=\"heading-anchor\" href=\"#what-s-next\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>El tutorial para principiantes finaliza aquí. Mientras tanto, es posible que desee ver algunos consejos sobre <a class=\"reference internal\" href=\"/es/3.1/intro/whatsnext/\"><span class=\"doc\">a dónde ir a partir de ahora</span></a>.</p>\n<p>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 <a class=\"reference internal\" href=\"/es/3.1/intro/reusable-apps/\"><span class=\"doc\">tutorial avanzado: Cómo escribir aplicaciones reutilizables</span></a>.</p>\n</section>","rootId":"writing-your-first-django-app-part-7","toc":[{"title":"Personalice el formulario del sitio administrativo","anchor":"customize-the-admin-form","children":[]},{"title":"Agregando objetos relacionados","anchor":"adding-related-objects","children":[]},{"title":"Personalice la lista de cambios del sitio administrativo","anchor":"customize-the-admin-change-list","children":[]},{"title":"Personalice el aspecto del sitio administrativo","anchor":"customize-the-admin-look-and-feel","children":[{"title":"Personalizando las plantillas de su proyecto","anchor":"customizing-your-project-s-templates","children":[]},{"title":"Personalizando las plantillas de su aplicación","anchor":"customizing-your-application-s-templates","children":[]}]},{"title":"Personalice la página del índice del sitio administrativo","anchor":"customize-the-admin-index-page","children":[]},{"title":"¿Qué sigue?","anchor":"what-s-next","children":[]}],"breadcrumbs":[{"docname":"intro/index","title":"Empezando","url":"/es/3.1/intro/"}],"prev":{"docname":"intro/tutorial06","title":"Escribiendo su primera aplicación en Django, parte 6","url":"/es/3.1/intro/tutorial06/"},"next":{"docname":"intro/reusable-apps","title":"Tutorial Avanzado: Cómo escribir aplicaciones reutilizables","url":"/es/3.1/intro/reusable-apps/"},"formats":{"html":"/es/3.1/intro/tutorial07/","markdown":"/es/3.1/intro/tutorial07.md","json":"/es/3.1/intro/tutorial07.json"},"source":"https://github.com/django/django/blob/stable/3.1.x/docs/intro/tutorial07.txt","official":"https://docs.djangoproject.com/es/3.1/intro/tutorial07/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}