Aspectos destacados de Django: disputa de activos estáticos y archivos multimedia (Parte 4)

Publicado: 2022-03-10
Resumen rápido ↬ Los desarrolladores y diseñadores front-end crean recursos estáticos increíbles para aplicaciones web. Hoy, nos estamos enfocando en lo que sucede después de que la revisión de estilo o el hermoso gráfico que acabas de terminar se vuelven maestros. También investigaremos el manejo de los archivos que cargan los usuarios, llamados archivos multimedia. Juntos, desarrollaremos una intuición de las estrategias disponibles para los desarrolladores de Django para entregar estos archivos a usuarios de todo el mundo de manera segura, eficiente y rentable.

Los sitios web de Django involucran muchos archivos. No es solo el código fuente para la configuración, los modelos, las vistas y las plantillas, sino también los activos estáticos: CSS y JavaScript, imágenes, íconos. Como si eso no fuera suficiente, a veces los usuarios vienen y quieren cargar sus propios archivos en su sitio web. Es suficiente para dejar incrédulo a cualquier desarrollador. ¡Archivos por todas partes!

Aquí es donde me gustaría poder decir (sin salvedades): “¡No te preocupes, Django te cubre las espaldas!” Pero desafortunadamente, cuando se trata de activos estáticos y archivos de medios, hay muchas advertencias con las que lidiar.

Hoy, abordaremos el almacenamiento y el servicio de archivos para implementaciones escalables y de un solo servidor mientras consideramos factores como la compresión, el almacenamiento en caché y la disponibilidad. También analizaremos los costos y beneficios de las CDN y las soluciones dedicadas de almacenamiento de archivos.

Nota : Este no es un tutorial sobre cómo implementar un sitio de Django en una plataforma específica. En su lugar, al igual que los otros artículos de la serie Django Highlights (ver más abajo), pretende ser una guía para que los desarrolladores y diseñadores front-end entiendan otras partes del proceso de creación de una aplicación web. Hoy, nos estamos enfocando en lo que sucede después de que la revisión de estilo o el hermoso gráfico que acabas de terminar se vuelven maestros. Juntos, desarrollaremos una intuición de las estrategias disponibles para los desarrolladores de Django para entregar estos archivos a usuarios de todo el mundo de manera segura, eficiente y rentable.

Piezas anteriores de la serie:

  • Parte 1: modelos de usuario y autenticación
  • Parte 2: Plantillas para guardar líneas
  • Parte 3: Modelos, administración y aprovechamiento de la base de datos relacional
¡Más después del salto! Continúe leyendo a continuación ↓

Definiciones

La mayoría de estos términos son bastante sencillos, pero vale la pena tomarse un momento para establecer un vocabulario compartido para esta discusión.

Los tres tipos de archivos en una aplicación Django en vivo son:

  1. Código fuente
    Los archivos de Python y HTML que se crean con el marco Django. Estos archivos son el núcleo de la aplicación. Los archivos de código fuente son generalmente bastante pequeños, medidos en kilobytes.
  2. Archivos estáticos
    También llamados "activos estáticos", estos archivos incluyen CSS y JavaScript, ambos escritos por el desarrollador de la aplicación y bibliotecas de terceros, así como archivos PDF, instaladores de software, imágenes, música, videos e íconos. Estos archivos solo se usan del lado del cliente. Los archivos estáticos van desde unos pocos kilobytes de CSS hasta gigabytes de video.
  3. Archivos multimedia
    Cualquier archivo cargado por un usuario, desde imágenes de perfil hasta documentos personales, se denomina archivo multimedia. Estos archivos deben almacenarse y recuperarse de manera segura y confiable para el usuario. Los archivos multimedia pueden ser de cualquier tamaño, el usuario puede cargar un par de kilobytes de texto sin formato a unos pocos gigabytes de video. Si se encuentra en el último extremo de esta escala, probablemente necesite un consejo más especializado que el que este artículo está preparado para brindar.

Los dos tipos de implementaciones de Django son:

  1. Servidor único
    Una implementación de Django de un solo servidor es exactamente lo que parece: todo vive en un solo servidor. Esta estrategia es muy simple y se parece mucho al entorno de desarrollo, pero no puede manejar cantidades de tráfico grandes o inconsistentes de manera efectiva. El enfoque de servidor único solo es aplicable para proyectos de aprendizaje o demostración, no para aplicaciones reales que requieren un tiempo de actividad confiable.
  2. Escalable
    Hay muchas formas diferentes de implementar un proyecto Django que le permite escalar para satisfacer la demanda de los usuarios. Estas estrategias a menudo implican activar y desactivar numerosos servidores y usar herramientas como balanceadores de carga y bases de datos administradas. Afortunadamente, podemos agrupar efectivamente todo lo que sea más complejo que una implementación de un solo servidor en esta categoría para los fines de este artículo.

Opción 1: Django predeterminado

Los proyectos pequeños se benefician de una arquitectura simple. El manejo predeterminado de activos estáticos y archivos multimedia de Django es solo eso: simple. Para cada uno, tiene una carpeta raíz que almacena los archivos y vive justo al lado del código fuente en el servidor. Sencillo. Estas carpetas raíz se generan y administran principalmente a través de la configuración yourproject/settings.py .

Activos estáticos

Lo más importante que hay que entender cuando se trabaja con archivos estáticos en Django es el comando python manage.py collectstatic . Este comando revisa la carpeta estática de cada aplicación en el proyecto Django y copia todos los activos estáticos en la carpeta raíz. Ejecutar este comando es una parte importante de la implementación de un proyecto Django. Considere la siguiente estructura de directorios:

 - project - project - settings.py - urls.py - ... - app1 - static/ - app1 - style.css - script.js - img.jpg - templates/ - views.py - ... - app2 - static/ - app2 - style.css - image.png - templates/ - views.py - ...

También asuma las siguientes configuraciones en project/settings.py :

 STATIC_URL = "/static/" STATIC_ROOT = "/path/on/server/to/djangoproject/static"

Ejecutar el comando python manage.py collectstatic creará la siguiente carpeta en el servidor:

 - /path/on/server/to/djangoproject/static - app1 - style.css - script.js - img.jpg - app2 - style.css - image.png

Observe que dentro de cada carpeta estática, hay otra carpeta con el nombre de la aplicación. Esto es para evitar conflictos de espacio de nombres después de recopilar los archivos estáticos; como puede ver en la estructura de archivos anterior, esto mantiene app1/style.css y app2/style.css distintos. Desde aquí, la aplicación buscará archivos estáticos en esta estructura en STATIC_ROOT durante la producción. Como tal, haga referencia a los archivos estáticos de la siguiente manera en una plantilla en app1/templates/ :

 {% load static %} <link rel="stylesheet" type="text/css" href="{% static "app1/style.css" %}">

Django averigua automáticamente de dónde obtener el archivo estático en desarrollo para modelar este comportamiento, no necesita ejecutar collectstatic durante el desarrollo.

Para obtener más detalles, consulte la documentación de Django.

Archivos multimedia

Imagine un sitio de redes profesionales con una base de datos de usuarios. Cada uno de esos usuarios tendría un perfil asociado, que podría contener, entre otras cosas, una imagen de avatar y un documento de currículum. Aquí hay un breve modelo de ejemplo de esa información:

 from django.db import models from django.contrib.auth.models import User def avatar_path(instance, filename): return "avatar_{}_{}".format(instance.user.id, filename) class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) resume = models.FileField(upload_to="path/string") avatar = models.ImageField(upload_to=avatar_path)

Para que esto funcione, necesita las siguientes opciones en project/settings.py , como con los activos estáticos:

 MEDIA_URL = "/media/" MEDIA_ROOT = "/path/on/server/to/media"

Un ImageField hereda de FileField , por lo que comparte los mismos parámetros y capacidades. Ambos campos tienen un argumento upload_to opcional, que toma una cadena que es una ruta y la agrega a MEDIA_ROOT para almacenar el archivo, al que luego se puede acceder por la misma ruta en la parte superior de MEDIA_URL . El argumento upload_to también puede tomar una función que devuelve una cadena, como se demuestra con la función avatar_path .

Asegúrese de omitir el directorio de archivos multimedia y su contenido del control de versiones. Su contenido puede entrar en conflicto cuando dos desarrolladores prueban la misma aplicación en diferentes máquinas y, a diferencia de los activos estáticos, no forma parte de la aplicación desplegable de Django.

Opción 2: Django con servicios

Mi filosofía rectora es utilizar las herramientas para lo que son mejores. Django es un marco increíble y proporciona excelentes herramientas listas para usar para la autenticación de usuarios, la representación del lado del servidor, el trabajo con modelos y formularios, funciones administrativas y docenas de otros aspectos esenciales de la creación de aplicaciones web. Sin embargo, sus herramientas para manejar activos estáticos y archivos multimedia no son, en mi opinión, adecuadas para la producción en sitios escalables. Los desarrolladores centrales de Django reconocen que muchas personas eligen enfoques alternativos para manejar estos archivos en producción; el marco es muy bueno para quitarse de en medio cuando lo hace. La mayoría de los sitios de Django destinados al uso general querrán incorporar activos estáticos y manejar archivos multimedia utilizando estos enfoques no específicos de Django.

Activos estáticos en un CDN

Si bien los proyectos pequeños y medianos pueden funcionar sin uno, una CDN (red de entrega de contenido) es fácil de usar y mejora el rendimiento de las aplicaciones de cualquier tamaño. Una CDN es una red de servidores, generalmente en todo el mundo, que distribuye y sirve contenido web, en su mayoría activos estáticos. Los CDN populares incluyen Cloudflare CDN, Amazon CloudFront y Fastly. Para usar un CDN, carga sus archivos estáticos, luego en su aplicación haga referencia a ellos de la siguiente manera:

 <link rel="stylesheet" type="text/css" href="https://cdn.example.com/path/to/your/files/app1/style.css">

Este proceso es fácil de integrar con sus scripts de implementación de Django. Después de ejecutar el comando python manage.py collectstatic , copie el directorio generado en su CDN (un proceso que varía sustancialmente según el servicio que esté usando), luego elimine los activos estáticos del paquete de implementación de Django.

En desarrollo, querrá acceder a diferentes copias de sus activos estáticos que en producción. De esta manera, puede realizar cambios localmente sin afectar el sitio de producción. Puede usar recursos locales o ejecutar una segunda instancia de CDN para entregar los archivos. Configure yourproject/settings.py con alguna variable personalizada, como CDN_URL , y use ese valor en sus plantillas para asegurarse de que está usando la versión correcta de los activos en desarrollo y producción.

Una nota final es que muchas bibliotecas para CSS y JavaScript tienen CDN gratuitos que la mayoría de los sitios web pueden usar. Si está cargando, por ejemplo, Bootstrap 4 o underscore.js, puede omitir la molestia de usar su propia copia en desarrollo y el gasto de servir sus propias copias en producción mediante el uso de estos CDN públicos.

Archivos multimedia con un almacén de archivos dedicado

Ningún sitio de producción de Django debe almacenar archivos de usuario en una carpeta simple /media/ en algún lugar del servidor que ejecuta el sitio. Aquí hay tres de las muchas razones por las que no hacerlo:

  1. Si necesita ampliar el sitio agregando varios servidores, necesita alguna forma de copiar y sincronizar los archivos cargados en esos servidores.
  2. Si un servidor falla, el código fuente se respalda en su sistema de control de versiones, pero los archivos multimedia no se respaldan de manera predeterminada, a menos que haya configurado su servidor para que lo haga, pero para ese esfuerzo, sería mejor que use un servidor dedicado. almacén de archivos.
  3. En caso de actividad maliciosa, es algo mejor mantener los archivos cargados por el usuario en un servidor separado del que ejecuta la aplicación, aunque esto de ninguna manera elimina el requisito de validar los archivos cargados por el usuario.

Integrar un tercero para almacenar los archivos subidos por el usuario es realmente fácil. No necesita cambiar nada en su código, excepto tal vez eliminar o modificar el valor upload_to de FileField s en sus modelos y configurar algunas configuraciones. Por ejemplo, si planeaba almacenar sus archivos en AWS S3, le gustaría hacer lo siguiente, que es muy similar al proceso de almacenamiento de archivos con Google Cloud, Azure, Backblaze o servicios similares de la competencia.

Primero, deberá instalar las bibliotecas boto3 y django-storages . Luego, debe configurar un depósito y un rol de IAM en AWS, que está fuera del alcance de este artículo, pero puede ver las instrucciones aquí. Una vez que todo esté configurado, debe agregar tres variables a su proyecto/configuración.py :

 DEFAULT_FILE_STORAGE = "storages.backends.s3boto3.S3Boto3Storage" AWS_STORAGE_BUCKET_NAME = "BUCKET_NAME" AWS_S3_REGION_NAME = "us-east-2"

Además, deberá configurar el acceso de credenciales a su depósito de AWS. Algunos tutoriales demostrarán cómo agregar una ID y una clave secreta a su archivo de configuración o como variables de entorno, pero estas son prácticas inseguras. En su lugar, use django-storages con la AWS CLI para configurar las claves, como se describe aquí. También puede estar interesado en la documentación django-storages .

No desea que los archivos multimedia de desarrollo o prueba se mezclen con las cargas de los usuarios reales. Evitar esto es bastante simple: configure varios cubos, uno para desarrollo (o uno para cada desarrollador), uno para pruebas y otro para producción. Luego, todo lo que necesita cambiar es la configuración de AWS_STORAGE_BUCKET_NAME por entorno y listo.

Rendimiento y disponibilidad

Existen numerosos factores que afectan el rendimiento y la confiabilidad de su sitio web. Estos son algunos importantes al considerar los archivos estáticos y multimedia que importan, independientemente del enfoque que adopte para administrarlos.

Costo

Entregar archivos a un usuario cuesta dinero por dos razones: almacenamiento y ancho de banda. Tiene que pagarle al proveedor de alojamiento para que almacene los archivos por usted, pero también tiene que pagarle para que sirva los archivos. El ancho de banda es sustancialmente más costoso que el almacenamiento (por ejemplo, AWS S3 cobra 2,3 centavos por gigabyte de almacenamiento frente a 9 centavos por gigabyte de transferencia de datos a Internet en el momento de escribir este artículo). La economía de un almacén de archivos como S3 o CDN es diferente a la economía de un host generalizado como una gota de Digital Ocean. Aproveche la especialización y las economías de escala trasladando archivos costosos a servicios diseñados para ellos. Además, muchos almacenes de archivos y CDN ofrecen planes gratuitos para que los sitios que pueden ser lo suficientemente pequeños como para salirse con la suya sin usarlos puedan hacerlo y aprovechar los beneficios sin costos de infraestructura adicionales.

Compresión y Transcodificación

La mayoría de los problemas causados ​​por activos estáticos como fotos y videos se deben a que son archivos grandes. Naturalmente, los desarrolladores abordan esto tratando de hacer estos archivos más pequeños. Hay varias formas de hacer esto utilizando una combinación de compresión y transcodificación en dos categorías generales: sin pérdida y con pérdida. La compresión sin pérdida conserva la calidad original de los activos, pero proporciona reducciones relativamente modestas en el tamaño del archivo. La compresión con pérdida, o la transcodificación a un formato con pérdida, permite tamaños de archivo mucho más pequeños a expensas de perder parte de la calidad del artefacto original. Un ejemplo de esto es la transcodificación de video a una tasa de bits más baja. Para obtener más información, consulta este artículo sobre cómo optimizar la entrega de videos. Al servir archivos grandes a través de la web, las velocidades de ancho de banda a menudo exigen que sirva artefactos altamente comprimidos, lo que requiere una compresión con pérdida.

A menos que sea YouTube, la compresión y la transcodificación no se realizan sobre la marcha. Los activos estáticos deben tener el formato adecuado antes de la implementación, y puede aplicar restricciones básicas de tipo y tamaño de archivo en las cargas de los usuarios para garantizar una compresión suficiente y un formato adecuado en los archivos multimedia de sus usuarios.

Minificación

Si bien los archivos de JavaScript y CSS no suelen ser tan grandes como las imágenes, a menudo se pueden comprimir para reducir los bytes. Este proceso se llama minificación. La minificación no cambia la codificación de los archivos, siguen siendo texto y un archivo minificado aún debe ser un código válido para su idioma original. Los archivos minimizados conservan sus extensiones originales.

Lo principal que se elimina en un archivo minimizado son los espacios en blanco innecesarios y, desde la perspectiva de la computadora, casi todos los espacios en blanco en CSS y JavaScript son innecesarios. Los esquemas de minificación también acortan los nombres de las variables y eliminan los comentarios.

La minificación por defecto ofusca el código; como desarrollador, debe trabajar exclusivamente con archivos no minificados. Algún paso automático durante el proceso de implementación debería minimizar los archivos antes de que se almacenen y sirvan. Si usa una biblioteca proporcionada por una CDN de terceros, asegúrese de usar la versión reducida de esa biblioteca, si está disponible. Los archivos HTML se pueden minimizar, pero como Django usa la representación del lado del servidor, el costo de procesamiento de hacerlo sobre la marcha probablemente supere la pequeña disminución en el tamaño de la página.

Disponibilidad mundial

Al igual que lleva menos tiempo enviar una carta a su vecino que enviarla a todo el país, también lleva menos tiempo transmitir datos cerca que al otro lado del mundo. Una de las formas en que una CDN mejora el rendimiento de la página es copiando activos en servidores de todo el mundo. Luego, cuando un cliente realiza una solicitud, recibe los activos estáticos del servidor más cercano (a menudo llamado nodo perimetral), lo que reduce los tiempos de carga. Una de las ventajas de usar una CDN con un sitio de Django es desvincular la distribución global de sus activos estáticos de la distribución global de su código.

Almacenamiento en caché del lado del cliente

¿Qué es mejor que tener un archivo estático en un servidor cerca de tu usuario? ¡Tener el archivo estático ya almacenado en el dispositivo de tu usuario! El almacenamiento en caché es el proceso de almacenar los resultados de un cálculo o solicitud para que se pueda acceder a ellos repetidamente con mayor rapidez. Al igual que una hoja de estilo CSS se puede almacenar en caché en todo el mundo en un CDN, se puede almacenar en caché en el navegador del cliente la primera vez que carga una página desde su sitio. Luego, la hoja de estilo está disponible en el propio dispositivo en las solicitudes posteriores, por lo que el cliente realiza menos solicitudes, mejora el tiempo de carga de la página y reduce el uso del ancho de banda.

Los navegadores realizan sus propias operaciones de almacenamiento en caché, pero si su sitio disfruta de un tráfico considerable, puede optimizar su comportamiento de almacenamiento en caché del lado del cliente utilizando el marco de trabajo de caché de Django.

En conclusión

Una vez más, mi filosofía rectora es utilizar las herramientas para lo que mejor se les da. Los proyectos de un solo servidor y las pequeñas implementaciones escalables con solo activos estáticos livianos pueden usar la gestión de activos estáticos integrada de Django, pero la mayoría de las aplicaciones deben separar los activos para que se sirvan a través de un CDN.

Si su proyecto está destinado a cualquier tipo de uso de palabras reales, no almacene archivos multimedia con el método predeterminado de Django, en su lugar use un servicio. Con suficiente tráfico, donde "suficiente tráfico" es un número relativamente pequeño en la escala de Internet, las complicaciones adicionales a la arquitectura, el proceso de desarrollo y la implementación valen más que la pena por el rendimiento, la confiabilidad y el ahorro de costos de usar un Solución separada de CDN y almacenamiento de archivos para archivos estáticos y multimedia, respectivamente.

Lectura recomendada

  • Parte 1: modelos de usuario y autenticación
  • Parte 2: Plantillas para guardar líneas
  • Parte 3: Modelos, administración y aprovechamiento de la base de datos relacional