Estáticos¶
Django básico
Los ficheros estáticos («assets») son ficheros que no necesitan un preprocesamiento y que se utilizan «tal cual son». Nos estamos refiriendo a:
- Imágenes.
- Vídeos.
- Fuentes tipográficas.
- Hojas de estilo CSS.
- Código JavaScript.
Estáticos en desarrollo¶
Siempre y cuando tengamos activada la aplicación 'django.contrib.staticfiles' (que ya viene por defecto) Django se encargará de servir los ficheros estáticos cuando así sea necesario.
Producción
Esto sólo es válido para un entorno de desarrollo, cuando pasamos a producción habrá que configurar el servidor web correspondiente para gestionar los ficheros estáticos.
Ubicación¶
Los ficheros estáticos «deberían» estar ubicados en la carpeta static de cada aplicación del proyecto. Cuando hacemos referencia a un estático usamos una ruta. Funciona de manera análoga a la ubicación de las plantillas.
Una aproximación inicial sería definir una hoja de estilos CSS y una carpeta de imágenes para todo el proyecto. Lo podríamos ubicar por ejemplo en la aplicación shared para que los recursos sean compartidos por todo el proyecto:
- La ruta para acceder a
base.cssseríacss/custom.css - La ruta para acceder a
logo.svgseríaimages/logo.svg
Django se encargará de rastrear las carpetas static de las aplicaciones para encontrar los estáticos indicados. Por lo tanto los espacios de nombres también son importantes a la hora de organizar los estáticos de nuestro proyecto Django.
Una buena práctica (en el caso de estáticos específicos de una aplicación concreta) es crear una subcarpeta con el nombre de la aplicación. Supongamos por ejemplo que queremos guardar ciertas imágenes específicas de un «post»:
- La ruta para acceder a
fav.pngseríaposts/images/fav.png - La ruta para acceder a
like.pngseríaposts/images/like.svg
Acceso a estáticos¶
En este apartado veremos cómo acceder a ficheros estáticos tanto desde una plantilla como desde una vista.
Hay dos variables importantes en settings.py que definen el comportamiento de los estáticos en un proyecto Django:
STATIC_URL: Define la URL que se utilizará cuando hagamos referencia a un fichero estático. Su valor por defecto es'static/'.STATICFILES_DIRS: Define directorios adicionales donde Django irá a buscar ficheros estáticos. Su valor por defecto es[].
Estáticos en plantillas¶
Para acceder a ficheros estáticos desde una plantilla Django debemos utilizar la etiqueta {% static %}.
Supongamos que tratamos de acceder a los ficheros estáticos definidos en el ejemplo anterior del «blog»:
{% load static %}<!--(1)!-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Blog</title>
<link rel="stylesheet" href="{% static 'css/base.css' %}"><!--(2)!-->
</head>
<body>
<header>
<img src="{% static 'images/logo.svg' %}"/><!--(3)!-->
</header>
<p>
I like this post
<img src="{% static 'posts/images/like.png' %}"/><!--(4)!-->
</p>
</body>
</html>
-
- Es necesario cargar la etiqueta
static. - Debería escribirse al principio de la plantilla, eso sí, siempre después de
{% extends %}que debe ser la primera..
- Es necesario cargar la etiqueta
- URL generada:
/static/css/base.css - URL generada:
/static/images/logo.svg - URL generada:
/static/posts/images/like.png
Caché
Los navegadores web tratan de cachear1 todo el contenido que pueden para así acelerar la carga de las páginas. Es por ello que, a veces, no verás reflejados los cambios en ciertos ficheros estáticos.
Si es tu caso, puedes probar a recargar el navegador sin caché:
Ctrl + F5
Ctrl + F5
Cmd + Shift + R
Estáticos en vistas¶
Lo más habitual es utilizar ficheros estáticos directamente en plantillas, pero puede darse el caso donde necesitemos acceso a los estáticos en las vistas. Se diferencian dos aproximaciones:
Acceso a la ruta en la URL.
Acceso a la ruta en el sistema de ficheros.
Para obtener la ruta en la URL de un determinado estático podemos utilizar la misma etiqueta static pero desde django.templatetags.static.
Veamos un ejemplo:
from django.templatetags.static import static as static_url#(1)!
def my_view(request):
# ...
like_url_path = static_url('posts/images/like.png')#(2)!
- Es necesario importar la función
static(). - En este caso se devolverá la URL
/static/posts/images/like.png
Para obtener la ruta en el sistema de ficheros de un determinado estático podemos utilizar la función path desde django.contrib.staticfiles.
Veamos un ejemplo:
from django.contrib.staticfiles.storage import path as static_path #(1)!
def my_view(request):
# ...
like_file_path = static_path('posts/images/like.png')#(2)!
- Es necesario importar la función
path(). - En este caso se devolverá la ruta
/home/guido/dev/blog/posts/static/posts/images/like.png
Bootstrap¶
Django avanzado
Bootstrap ofrece un conjunto de herramientas que facilitan el desarrollo de interfaces «frontend» para aplicaciones web.
En el momento de la escritura de este documento, Bootstrap figura entre los 30 proyectos con más
de GitHub2.
Instalación¶
Hay varias maneras de instalar Bootstrap y de integrarlo en un proyecto Django. En esta sección veremos cómo implantarlo usando npm y acceso a ficheros estáticos.
Lo primero será instalar los paquetes JavaScript correspondientes:
- Desde el raíz de nuestro proyecto Django.
El comando anterior creará una carpeta node_modules con multitud de ficheros y subcarpetas, correspondientes a los paquetes Node instalados y a todas sus dependencias.
Control de versiones
Recuerda excluir la carpeta node_modules del control de versiones añadiéndola al fichero .gitignore de tu proyecto.
También crearán dos ficheros de seguimiento de paquetes (1):
package.jsonque almacena las versiones (mínimas) de los paquetes instalados.package-lock.jsonque almacena las dependencias de los paquetes instalados.
-
En el caso de utilizar
uv(gestión de paquetería Python), podríamos decir que:package.json\(\approx\)pyproject.tomlpackage-lock.json\(\approx\)uv.lock
Configuración¶
Para poder acceder a los archivos creados en node_modules desde las plantillas Django, necesitamos especificar en la configuración del proyecto que dicha carpeta contiene estáticos.
Para ello añadimos la siguiente línea al fichero settings.py:
-
- Esta variable permite añadir rutas extras donde Django irá a buscar ficheros estáticos.
- Puedes añadirla donde quieras, pero un buen lugar podría ser junto a la variable
STATIC_URL.
Plantillas¶
Dado que Bootstrap utiliza ficheros .css y .js necesitamos cargarlos correctamente desde nuestras plantillas.
Suponiendo que disponemos de una plantilla base tendríamos que añadir lo siguiente:
{% load static %}<!--(1)!-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title></title>
<link rel="stylesheet" href="{% static 'bootstrap/dist/css/bootstrap.min.css' %}"><!--(2)!-->
<link rel="stylesheet" href="{% static 'bootstrap-icons/font/bootstrap-icons.min.css' %}"><!--(3)!-->
<link rel="stylesheet" href="{% static 'css/custom.css' %}"><!--(4)!-->
</head>
<body>
<div class="container"><!--(5)!-->
{% block content %}
{% endblock %}
</div>
</body>
<script type="text/javascript" src="{% static 'bootstrap/dist/js/bootstrap.bundle.min.js' %}"></script><!--(6)!-->
</html>
- Necesitamos cargar las utilidades para estáticos.
- Cargamos los estilos de Bootstrap.
- Cargamos los iconos de Bootstrap.
- Cargamos estilos propios (opcional).
- La clase
containeres el bloque fundamental de Bootstrap. - Cargamos los scripts de Bootstrap.
A partir de aquí ya podremos usar todos los recursos que nos proporciona Bootstrap para diseñar una interfaz de usuario moderna, responsiva y funcional.
Modales¶
La implementación de ventanas modales suele ser una estrategia interesante para confirmar acciones y mostrar mensajes informativos.
A continuación se presenta una propuesta de modal con Bootstrap mediante una etiqueta personalizada poniendo como ejemplo de uso su aplicación al borrar un «post» del «blog»:
import uuid
from django import template
from django.urls import reverse
register = template.Library()
@register.inclusion_tag('includes/modal.html')
def modal(
btn_text,#(1)!
url,#(2)!
*url_args,#(3)!
title='Attention',#(4)!
body='Are you sure to continue?',#(5)!
action='Continue',#(6)!
btn_classes='btn btn-primary',#(7)!
btn_icon='',#(8)!
):
url = reverse(url, args=url_args)
modal_id = uuid.uuid4()
return dict(
modal_id=modal_id,
title=title,
body=body,
action=action,
url=url,
btn_text=btn_text,
btn_classes=btn_classes,
btn_icon=btn_icon,
)
- Texto del botón que lanza el modal.
- Nombre de URL a ejecutar si se «confirma» el modal.
- Argumentos para conformar la URL.
- Título de la ventana modal.
- Texto para el cuerpo de la ventana modal.
- Texto del botón de confirmación en la ventana modal.
- Clases CSS a aplicar sobre el botón que lanza el modal.
- Icono a mostrar en el botón que lanza el modal.
<!-- ↓ Button to launch modal -->
<button type="button" class="{{ btn_classes }}" data-bs-toggle="modal" data-bs-target="#{{ modal_id }}">
<i class="{{ btn_icon }}"></i>
{{ btn_text }}
</button>
<!-- ↓ Modal window -->
<div class="modal fade" id="{{ modal_id }}" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">{{ title }}</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{{ body }}
</div>
<div class="modal-footer">
<a href="{{ url }}" class="btn btn-primary">{{ action }}</a>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
-
Guardar copias de datos de forma temporal en una ubicación de almacenamiento más rápida. ↩
-
Información via git-stars.org. ↩