Renderizar templates en Django



@eduardo_gpg

Número de visitas 3560

Tiempo de lectura 5 min

6 Diciembre 2020

Cómo se ha mencionado anteriormente, Django es un Framework Web que utiliza el patron de diseño MTV, por su siglas al ingles: Model, Template, Views. Pudiendo así separar nuestra lógica de negocios con la presentación de los datos.

Si bien es cierto, el cómo almacenar, obtener y procesar la información es pieza clave para nuestros proyectos, el cómo será visualizada también lo es. Vaya, me atrevo a decir que, en la mayoría de los casos, el definir cómo el usuario podrá visualizar la información jugará un papel clave en la estrategia para obtener y procesar los datos. 😋

Y es por esta razón que, en esta ocasión, me gustaría abordáramos el tema de templates en Django. Explicaremos las diferentes formas de obtener y renderizar templates, además de los tipos de usos que podemos darles.

Es sin duda un tema bastante interesante, y al cual sin duda le podrás sacar mucho provecho. Bien, sin más introducción, comencemos.

Templates

Comencemos con lo básico, ¿Qué es un template? Podemos definir un template como el archivo a través del cual el usuario podrá visualizar la información que solicita. Comúnmente asociamos los templates para archivos .html y, si bien es cierto, estamos en lo correcto, en Django no es el único tipo de archivo que podemos utilizar. De igual forma podemos presentar la información en archivos .XML, .YAML, .JSON etc.. Esto gracias al fabuloso motor de Template que posee el Framework. 🥳

Aquí un pequeño ejemplo para pintar el username de los últimos usuarios obtenidos.

<div class="col-6">
    <h5>Últimos tokens generados.</h5>
    <ul>
        {% for user in last_users %}
            <li> {{ user.username }} </li>
            {% if user.active %}
                <p>Usuario activo</p>
            {% endif %}
        {% endfor %}
    </ul>
</div>

Cómo podemos observar, dentro de los template podemos hacer uso de sentencias Python, como lo pueden ser ciclos y/o condicionales. Esto es algo que nos viene de maravillas para poder crea páginas web dinámicas, páginas la cuales se creen en cuestión a las necesidades del usuario, pudiendo pintar diferentes bloques de información dependiendo cuál sea el caso.

Y ahora, si eres nuevo en Django, quizás te estes preguntando ¿Cómo puedo utilizar los templates para pintar la información que deseo? La respuesta puede ser algo extensa, ya que existen múltiples formas de hacerlo, pero comencemos con la más sencilla, con la función render.

Función render

La función render, tal y como su nombre nos indica, nos permite renderizar un template. Así de sencillo. La función nos será de mucha útilidad cuando deseamos responder a la petición de un cliente mediante alguna página web, o ¿por qué no? también podemos utilizar para crear nuestros propios correo electrónicos. ✉

La función podemos encontrarla dentro del módulo shortcuts.

from django.shortcuts import render

Esta función recibe como argumento, de forma obligatoria, 3 valores. La petición per se, el template a renderizar y un contexto. El contexto no será más que un diccionario cuyas llaves podrán ser utilizadas dentro del template.

Aquí un ejemplo.

def premium(request, slug):
    article = get_object_or_404(Article, slug=slug)

    return render(request, 'articles/premium.html', {
        'article': article,
    })

Para este ejemplo enviamos el objeto Article al nuestro template, pudiendo así utilizarlo para crear una página web dinámica, accediendo y condicionando, o iterando, sobre cada uno de sus atributos o métodos. 🤠

<h1>{{ article.title }}</h1>
<p>
    {{ article.content }}
</p>

Ahora, es importante mencionar que, por default, Django buscará el template dentro del folder template de nuestras aplicaciones.

Por ejemplo, para nuestra aplicación articles el path sería el siguiente: articles/templates/articles/premium.html

Un poco confuso ¿No? bueno para mí lo fue al principio. Tener que crear el folder template para cada una de nuestras aplicaciones puede resultar en algo tedioso, necesario, pero tedioso. 😣 Afortunadamente hay forma de solucionarlo.

Y ahora ¿Qué pasa si no me encuentro trabajando con ningún tipo de aplicación o simplemente quiero especificar otro folder en dónde deseo almacenar mis templates? Bueno, en esos casos Django nos ofrece una pequeña alternativa. En nuestro archivo settings.py debemos modificar la constante TEMPLATES.

Dentro del listado, para la llave DIRS, vamos a colocar el nombre de nuestro folder en dónde pretendemos almacenar nuestros templates.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['templates'],
        'APP_DIRS': True,
        'OPTIONS': {
         ...
        },
    },
]

Al nosotros hacer esto, siempre que renderizemos un template, Django primero buscará dicho archivo en el folder (o folders) que hayamos indicados en el archivo de configuración, en caso el folder no se encuentre allí, se hará la búsqueda dentro de la aplicación pertinente, y en caso de tampoco encontrarlo, el error TemplateDoesNotExist será lanzado.

Nota: La función render retornar un objeto de tipo HTTPResponse, por lo que es posible almacenarlo en una variable para posteriormente manipularlo. Algo que ya estaremos viendo en otra entrega. 🥳

response = render(request, 'subscriptions/subscription.html', context)
response.set_cookie('coupon_code', coupon.code)

return response

Obtener template

Otra forma de poder obtener y renderizar un template, es mediante la función get_template. Esta función recibe cómo argumento la ruta del template a utilizar, y retorna un objeto de tipo template. Utilizando el método render del objeto, seremos capaces de renderizar nuestro template.

Aquí un ejemplo para crear un correo electrónico a partir de un template con etiquetas html.

from django.template.loader import get_template
from django.core.mail import EmailMultiAlternatives

template = get_template('users/mails')
content = template.render(
    {
        'user': user
    }
)

msg = EmailMultiAlternatives(
    subject, 
    'PyWombat',
    settings.FROM_EMAIL,
    [user.email],
)


msg.attach_alternative(content, 'text/html')

Vistas basadas en clases.

Si bien la función render podemos utilizarla prácticamente en cualquier parte del proyecto, es comúnmente implementada para las vistas en funciones; tal y como pudimos observar en el ejemplo anterior. Pero, ¿Qué pasa si nos encontramos implementado vistas basadas en clase? Pff, pues allí las cosas cambiar radicalmente. O bueno, no tanto así, pero sí cambian. 😅

Verás, las vistas basadas en clase tienen como objetivo agilizar el proceso de desarrollo, implementando ciertas convenciones para ello. Veamos un ejemplo.

class ArticleDetailView(DetailView):
    model = Article

En este caso, mi clase al tener por nombre ArticleDetailView y heredar de la clase DetailView, se buscará por default el template: articles/article_detail.html dentro de la aplicación articles. La convención sería la siguiente: nuestro modelo / el nombre de nuestra clase (con nomenclatura snake case) + .html. Esto puede funcionar para muchos, para mí no.

Afortunadamente Django nos da la facilidad de poder definir de forma muy puntual con qué template queremos trabajar. Esto gracias al tributo template_name y el método get_template_names. Vamos uno a uno.

Utilizando el atributo template_name indicaremos explícitamente el template a renderizar, evitando así utilizar el default de la clase. 🐙

class ArticleDetailView(DetailView):
    model = Article
    template_name = 'articles/detailt.html'

De forma personal me hace mucho más sentido utilizar el template detail.html que se almacena en folder article que la ruta: articles/article_detail.html (Una doble redundancia).

Esto funcionará perfectamente siempre que deseemos utilizar el mismo template para todas las peticiones. Sin embargo, en caso el template a utilizar depende completamente de ciertas condiciones deberemos apoyarnos del método get_template_names.

El método get_template_names retorna un listado de templates a renderizar. El primer template será el que se utilizará 😱

Ejemplo.

def get_template_names(self):
    if not self.request.user.is_anonymous:
        return ['articles/detail.html']
    else:
        return ['articles/subscription.html']

En este caso el template a renderizar depende completamente en si el usuarios de encuentra autenticado o no. Cómo podemos observar dependiendo cual sea el caso se hará uso de uno u otro template.

Por supuesto, esta es una condición bastante sencilla, no dudo que tú podrás sacarle mucho más provecho. 😋

Ojo, es importante mencionar que el renderizar un template u otro no tiene absolutamente nada que ver con re dirigir al usuario. Recuerda que los templates nos permitirán mostrar de diferentes formas.

Conclusión

Listo, en esta entrega aprendimos un par de cosas acerca de los templates, principalmente el cómo poder utilizarlos. Si bien estas no son las únicas formas de hacerlo, de hecho hay un par más, que implican, ya sea el uso de nuevas clases o inclusive middlewares, si consideró son las más comunes, y con las cuales sin dudas estaremos trabajando en nuestro día a día como desarrollador Django. 🍻


¿El contenido te resulto de ayuda?

Para poder dejar tu opinión es necesario ser un usuario autenticado. Login

Más Tips y Ejercicios 🐍

Adquiere una subscripción PyWombat por tan solo $3 USD. al mes.

Conoce los beneficios de ser usuario premium:
Niveles desbloqueados: Ten accesos a todos los niveles de ejercicios. 🔓
Nuevo límite: Incrementa tu límite de ejercicios por semana. 🚀
Contenido único: Recibe semanalmente recursos exclusivos de Python (Videos, Artículos y Capitulos del libro PyWombat, comienza como desarrollador Python. 🐍