Learn web development

Tutorial de Django Parte 5: Creación de tu página de inicio

Traducción en curso

Estamos listos ahora para añadir el código para mostrar nuestra primera página entera — una página de inicio del sitio web de la BibliotecaLocal que muestra cuántos registros tenemos de cada tipo de modelo y proporciona una barra lateral con enlaces de navegación a nuestras otras páginas. Por el camino ganaremos experiencia práctica en escritura básica de mapeos de URL y vistas, obtención de resgistros de la base de datos y uso de plantillas.

Pre-requisitos: Lee la Introducción a Django. Completa los tópicos previos del tutorial (incluyendo Tutorial de Django Parte 4: Sitio de administración de Django).
Objetivo: To understand how to create simple url maps and views (where no data is encoded in the URL), and how to get data from models and create templates.

Visión General

Ahora que hemos definindo nuestros modelos y hemos creado los primeros registros en la librería para trabajar, es hora de escribir código para presentar información a los usuarios. Lo primero que necesitamos es determinar que información queremos mostrar en nuestras páginas, y definir una URL apropiada hacia estos recursos. Vamos a necesitar crear el mapeador de URLs, las vistas y plantillas para mostrar estas páginas.

El siguiente diagrama es un recordatorio del principal flujo de datos y cosas necesarias para ser implementadas cuando se maneja una respuesta/petición en HTTP.
Los principales elementos que necesitamos crear son:

  • Mapeadores URL para reenviar las URLs admitidas (y cualquier información codificada en las URLs)  a las funciones de vista apropiadas.
  • Funciones de vista para obtener los datos solicitados desde los modelos, crear una página HTML que muestre los datos, y devolverlo al usuario para que lo vea en el navegador.
  • Plantillas usadas por las vistas para renderizar los datos.

Como verás en la siguiente sección, vamos a tener 5 páginas para mostrar, que es mucho que documentar en un artículo. Por lo tanto, en la mayor parte de este artículo nos concentraremos en mostrar como implementar solo la página de inicio (nos moverermos a otras páginas en un artículo subsecuente). Esto debe darte un buen entendimiento de extremo a extremo sobre como los mapeadores URL, vistas y modelos funcionan en la práctica.

Definiendo el recurso URL

Como esta versión de LocalLibrary  es escencialmente solo de lectura para usuarios finales, debemos proveer una página de llegada para el sitio (una página de inicio), y páginas que desplieguen listas y vistas detalladas para libros y autores. 

Las URL que vamos a necesitar para nuestras páginas son:

  • catalog/ — La página home/index.
  • catalog/books/ — La lista de todos los libros.
  • catalog/authors/ — La lista de todos los autores.
  • catalog/book/<id> — La vista detallada para el libro específico con un campo de clave primaria de <id> (el valor por defecto). Así por ejemplo, /catalog/book/3, para el tercer libro añadido.
  • catalog/author/<id> — La vista detallada para el autor específico con un campo de clave primaria llamada <id>. Así por ejemplo, /catalog/author/11, para el 11vo autor añadido.

La tres primeras URLs son usadas para listar el índice, los libros y autores. Esto no codifica ninguna información adicional, y mientras los resultados retornados dependerán del contenido en la base de datos, las consultas que se ejecutan para obtener la información siempre serán las mismas.

En contraste las 2 URLs finales son usadas para mostrar información detallada sobre un libro o autor específico — estas codifican la identidad de los ítemes a mostrar en la URL (mostrado arriba como <id> ). El mapeador URL puede extraer la información codificada y pasársela a la vista, donde se detarminará que información extraer de la base de datos. Al codificar la información en nuestra URL solo necesitamos un mapeador de URL, una vista, y un plantilla para manejar cada libro (o autor). 

Nota: Django te permite construir tus URLs  de cualquier forma que quieras — puedes codificar información en el cuerpo de la URL como se muestra arriba o usando la obtención de  parámetros GET  de la URL(e.j. /book/?id=6). Culquier enfoque que uses, las URLs deben mantenerse limpias, lógicas y legibles (observa el consejo del W3C aquí).

La documentación Django tiende a recomendar la codificación de información en el cuerpo de la URL, una práctica que ellos creen que promueve mejores diseños de URL.

Como discutimos en la introducción, el resto de este articulo describe como construimos la página index.

Creando la página index

La primera página que crearemos será la página index (catalog/). Esto desplegará un pequeño HTML estático, junto con algunos "contadores" calculados de diferentes registros en la base de datos. Para hacer este trabajo tendremos que crear un mapeador URL, una vista y una plantilla. 

Nota: Vale la pena prestar un poco de atención extra en esta sección. La mayoría del contenido es común para todas las páginas.

Mapeador URL

Hemos creado un archivo básico /catalog/urls.py para nuestra apliación catálogo cuando creamos el esqueleto del sitio Web. Las URLs de la apliación catálogo fueron incluidas dentro del proyecto con un mapeador a catalog/, entonces las URLs  que llegan a este mapeador deben empezar con catalog/ (el mapeador funciona sobre todos los string en la URL después de la barra diagonal).

Abra urls.py y pegue la línea en negrita que aparece a continuación. 

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

Esta función url() define un patrón URL (r'^$'),  y una función vista que será llamada si el patrón es detectado (views.index — una función llamada index() en views.py). El patrón URL es una expresión regular de Python (ER). Hablaremos un poco más sobre ERs más adelante en este tutorial, pero para este caso todo lo que necesitas saber es que en una ER de ^$  el patrón coincidirá con una cadena vacía  (^ es un marcador de inicio de cadena y  $ es un marcador de fin de cadena). 

Nota: Nota que en  /locallibrary/locallibrary/urls.py 

urlpatterns += [
    url(r'^catalog/', include('catalog.urls')),
]

La expresión regular en este caso no tienen un $ (caracter asignado a fin-de-cadena) pero incluye una barra diagonal. Siempre cuando Django se encuentra con include() (django.conf.urls.include()), corta cualquier parte de la URL que coincida hasta este punto y envía el resto de la cadena para incluir la configuración URL para el siguiente procesamiento.

La URL coincidente es en realidad catalog/ + <cadena vacía> ( /catalog/ es asumida ya que include() fue el método usado). Nuestra primera función vista  será llamada si recibimos una consulta HTTP con una URL de /catalog/.

La función  url() también especifica un parámetro name, que identifica de manera única  este mapeador de URL particular. Puedes usar este nombre para "revertir" el mapeador — para crear dinámicamente una URL que apunta al el recurso que el mapeador esta diseñado para manejar. Por ejemplo, con esto hecho ahora podemos enlazar nuestra página inicio creando el siguiente enlace en nuestra plantilla:

<a href="{% url 'index' %}">Home</a>.

Nota: Por su puesto podemos codificar a fuerza bruta el link anterior (e.j. <a href="/catalog/">Home</a>), pero entonces si cambiamos el patrón para nuestra página de inicio (e.j. a /catalog/index) la plantilla no podrá seguir enlazando correctamente. Usar un mapeador de url es mucho más flexible y robusto!

Vista (basada-en-funciones)

Una vista es una función que procesa una consulta HTTP, trae datos desde la base de datos cuando los necesita, genera una página HTML renderizando estos datos unando una plantilla HTML, y luego retorna el HTML en una respuesta HTTP para ser mostrada al usuario. La vista del índice sigue este modelo — extrae información sobre cuantos Book, BookInstanceBookInstance disponibles y registros Author tenemos en la base de datos, y los pasa a una plantilla para mostrarlos.

Abre catalog/views.py, y nota que el archivo ya importa el atajo de la función render() que genera archivos HTML usando una plantilla y datos. 

from django.shortcuts import render

# Create your views here.

Copia el siguiente código al final del archivo. La primera linea importa las clases de los modelos que usaremos para acceder a los datos en todas nuestras vistas.

from .models import Book, Author, BookInstance, Genre

def index(request):
    """
    Función vista para la página inicio del sitio.
    """
    # Genera contadores de algunos de los objetos principales
    num_books=Book.objects.all().count()
    num_instances=BookInstance.objects.all().count()
    # Libros disponibles (status = 'a')
    num_instances_available=BookInstance.objects.filter(status__exact='a').count()
    num_authors=Author.objects.count()  # El 'all()' esta implícito por defecto.
    
    # Renderiza la plantilla HTML index.html con los datos en la variable contexto
    return render(
        request,
        'index.html',
        context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors},
    )

La primera parte de la función vista extrae contadores de registros usando el atributo objects.all() en las clases del modelo. Tambien obtiene una lista de los objetos BookInstance  que tienen un valor del campo status de  'a' (Disponible). Puedes encontrar un poco más sobre cómo acceder desde modelos en nuestro tutorial previo (Django Tutorial Part 3: Usando modelos > Buscando registros).

Al final de la función invocamos a la función render()  para crear y retornar una página  HTML como una respuesta (esta función atajo envuelve una serie, simplicando este caso de uso muy común). Esta recibe como parametros el objeto request original (una ConsultaHttp), una plantilla HTML con marcadores para los datos, y una variable de contexto (un diccionario Python que contiene los datos que serán insertados en esos marcadores). 

Hablaremos más sobre la plantilla y la variable de contexto en la siguiente sección; vamos a crear nuestra plantilla para así de hecho mostrarle algo al usuario!

Plantilla

Una plantilla es un archivo de texto  que determina la estructura o diseño de un archivo (como una página HTML), con marcadores usados para representar el contenido real. Django automaticamente buscará plantillas en un directorio llamado 'templates' de su aplicación. Así por ejemplo, en la vista índice que acabamos de agregar, la función render() esperará poder encontrar el archivo /locallibrary/catalog/templates/index.html, y entregará un error si el archivo no puede ser encontrado. Puede ver esto si guarda los cambios anteriores y vuelve a su navegador — accediendo a 127.0.0.1:8000 ahora le entregará un mensaje de error bastante intuitivo "TemplateDoesNotExist at /catalog/", más otros detalles.

Nota: Django buscará en una serie de lugares por plantillas, basandose en su archivo de configuraciones de proyectos (buscar en su aplicación instalada es una configuración por defecto!). Puede encontrar más sobre como Django encuentra plantillas y qué formatos de plantillas soporta Templates (Django docs).

Plantillas extendidas

La plantilla índice va a necesitar marcado HTML estándar para la cabecera y el cuerpo, junto con secciones para navegar (a otras páginas en el sitio que todavía no hemos creado) y para mostrar algún texto introductorio y nuestros datos de libro. La mayoría de este texto (el HTML y la estructura de navegación) será el mismo para cada página en nuestro sitio. En lugar de obligar a los desarrolladores a duplicar este texto en cada página, el lenguaje de plantillas de Django le permite declarar una plantilla base y luego extenderla, reemplazando solo las porciones que son distintos para cada página específica. 

Por ejemplo, un plantilla base base_generic.html podría verse como el texto de abajo. Como puedes ver, este contiene algo de HTML "común"  y secciones para el título, barra lateral, y contendio marcados usando las etiquetas de plantillas llamadas block y endblock  (mostradas en negrita). Los bloques pueden estar vacíos, o tener contenido que será usado "por defecto" para páginas derivadas.

Nota: Las etiquetas de plantilla son como funciones que puede usar en una plantilla para recorrer listas, realizar operaciones condicionales basadas en el valor de una variable, etc. Además de las etiquetas de plantilla, la sintaxis de plantilla te permite referenciar variables de plantilla (que son pasadas en la plantilla desde la vista)  y usar  filtros de plantilla, que reformatean las variables (por ejemplo, establecer una cadena en minúsculas).

<!DOCTYPE html>
<html lang="en">
<head>
  {% block title %}<title>Local Library</title>{% endblock %}
</head>

<body>
  {% block sidebar %}<!-- insert default navigation text for every page -->{% endblock %}
  {% block content %}<!-- default content text (typically empty) -->{% endblock %}
</body>
</html>

Cuando queremos definir una plantilla para una vista en particular, primero especificamos la plantila base  (con la etiqueta de plantilla  extends — vea el código siguiente). Si ahí hay alguna seccón que queremos reemplazar en la plantilla declaramos esto, usando secciones block/endblock  idénticas a las usadas en la plantilla base.

Por ejemplo, el fragmento de código que sigue muestra como usar la etiqueta de plantilla extends, y sobrescribe el bloque content. El HTML final producido tendrá todo el HTML y la estructura defininda en la plantilla base (incluyendo el contenido por defecto que ha definido dentro del bloque title), pero con tu nuevo bloque content insertado en lugar del que venía por defecto.

{% extends "base_generic.html" %}

{% block content %}
<h1>Local Library Home</h1>
<p>Welcome to <em>LocalLibrary</em>, a very basic Django website developed as a tutorial example on the Mozilla Developer Network.</p>
{% endblock %}

La plantilla base de LocalLibrary

La plantilla base que pensamos usar para el siito web LocalLibrary se muestra abajo. Como puedes ver, contiene algo de HTML y bloques definidos para title, sidebar y content. Tenemos un título por defecto (que podríamos querer cambiar) y una barra lateral por defecto con enlaces a listas de todos los libros y autores (que probablemente no querramos cambiar, pero hemos dejado abierta la posibilidad de hacerlo si es necesario, poniéndolo en un bloque).

Nota: También introducimos dos etiquetas de plantilla adicionales: url y load static. Se discute sobre ellas en secciones posteriores.

Crea un nuevo archivo -- /locallibrary/catalog/templates/base_generic.html -- y pon en él el siguiente contenido:

<!DOCTYPE html>
<html lang="en">
<head>
  
  {% block title %}<title>Local Library</title>{% endblock %}
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
  
  <!-- Add additional CSS in static file -->
  {% load static %}
  <link rel="stylesheet" href="{% static 'css/styles.css' %}">
</head>

<body>

  <div class="container-fluid">

    <div class="row">
      <div class="col-sm-2">
      {% block sidebar %}
      <ul class="sidebar-nav">
          <li><a href="{% url 'index' %}">Home</a></li>
          <li><a href="">All books</a></li>
          <li><a href="">All authors</a></li>
      </ul>
     {% endblock %}
      </div>
      <div class="col-sm-10 ">
      {% block content %}{% endblock %}
      </div>
    </div>

  </div>
</body>
</html>

La plantilla usa (e incluye) JavaScript y CSS desde Bootstrap para mejorar el diseño y la presentación de la página HTML. Usar Bootstrap u otro framework web del lado del cliente es una manera rápida de crear una página atractiva que puede escalarse bien en diferentes tamaños de navegador, y también nos permite concentrarnos en la presentación de la página sin tener que entrar en ninguno de los detalles -- ¡queremos enfocarnos nada más en el código del lado del servidor aquí!

La plantilla base también hace referencia a un archivo css local (styles.css) que brinda algo más de estilo. Crea /locallibrary/catalog/static/css/styles.css y pon en él el siguiente contenido:

.sidebar-nav {
    margin-top: 20px;
    padding: 0;
    list-style: none;
}

The index template

Create the HTML file /locallibrary/catalog/templates/index.html and give it the content shown below. As you can see we extend our base template in the first line, and then replace the default content block with a new one for this template. 

{% extends "base_generic.html" %}

{% block content %}
<h1>Local Library Home</h1>

  <p>Welcome to <em>LocalLibrary</em>, a very basic Django website developed as a tutorial example on the Mozilla Developer Network.</p>

<h2>Dynamic content</h2>

  <p>The library has the following record counts:</p>
  <ul>
    <li><strong>Books:</strong> {{ num_books }}</li>
    <li><strong>Copies:</strong> {{ num_instances }}</li>
    <li><strong>Copies available:</strong> {{ num_instances_available }}</li>
    <li><strong>Authors:</strong> {{ num_authors }}</li>
  </ul>

{% endblock %}

In the Dynamic content section we've declared placeholders (template variables) for the information we wanted to include from the view.  The variables are marked using the "double brace" or "handlebars" syntax (see in bold above).

Note: You can easily recognise whether you're dealling with template variables or template tags (functions) because the variables have double braces ({{ num_books }}) while the tags are enclosed in single braces with percentage signs ({% extends "base_generic.html" %}).

The important thing to note here is that these variables are named with the keys that we passed into the context dictionary in our view's render() function (see below); these will be replaced by their associated values when the template is rendered.  

return render(
    request,
    'index.html',
     context={'num_books':num_books,'num_instances':num_instances,'num_instances_available':num_instances_available,'num_authors':num_authors},
)

Referencing static files in templates

Your project is likely to use static resources, including JavaScript, CSS, and images. Because the location of these files might not be known (or might change), Django allows you to specify the location of these files in your templates relative to the STATIC_URL global setting (the default skeleton website sets the value of STATIC_URL to '/static/', but you might choose to host these on a content delivery network or elsewhere).

Within the template you first call the load template tag specifying "static" to add this template library (as shown below). After static is loaded, you can then use the static template tag, specifying the relative URL to the file of interest.

 <!-- Add additional CSS in static file --> 
{% load static %} 
<link rel="stylesheet" href="{% static 'css/styles.css' %}">

You could if desired add an image into the page in the same sort of fashion. For example:

{% load static %}
<img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="My image" style="width:555px;height:540px;"/>

Note: The changes above specify where the files are located, but Django does not serve them by default. While we enabled serving by the development web server in the global URL mapper (/locallibrary/locallibrary/urls.py) when we created the website skeleton, you will still need to arrange for them to be served in production. We'll look at this later.

For more information on working with static files see Managing static files (Django docs).

Linking to URLs

The base template above introduced the url template tag.

<li><a href="{% url 'index' %}">Home</a></li> 

This tag takes the name of a url() function called in your urls.py and values for any arguments the associated view will receive from that function, and returns a URL that you can use to link to the resource.

What does it look like?

At this point we should have created everything needed to display the index page. Run the server (python3 manage.py runserver) and open your browser to http://127.0.0.1:8000/. If everything is set up correctly, your site should look something like the following screenshot.

Index page for LocalLibrary website

Note: You won't be able to use the All books and All authors links yet, because the urls, views, and templates for those pages haven't been defined (currently we've just inserted placeholders for those links in the base_generic.html template).

Challenge yourself

Here are a couple of tasks to test your familiarity with model queries, views and templates. 

  1. Declare a new title block in the index template and change the page title to match this particular page.
  2. Modify the view to generate a count of genres and a count of books that contain a particular word (case insensitive) and then add these fields to the template.

Summary

We've now created the home page for our site — an HTML page that displays some counts of records from the database and has links to our other still-to-be-created pages. Along the way we've learned a lot of fundamental information about url mappers, views, querying the database using our models, how to pass information to a template from your view, and how to create and extend templates.

In our next article we'll build on our knowledge to create the other four pages.

See also

 

In this module

 

Etiquetas y colaboradores del documento

Colaboradores en esta página: cristianaguilarvelozo, AnPlandolit, javierdelpino
Última actualización por: ricardo-soria,