Servir y organizar recursos estáticos en Django

Django se centra en la parte dinámica de una aplicación web, pero una página completa también necesita imágenes, hojas de estilo y JavaScript. En proyectos pequeños basta con copiar estos ficheros a cualquier carpeta accesible, pero cuando crecen y se dividen en varias apps la tarea se vuelve engorrosa. La aplicación django.contrib.staticfiles automatiza la recopilación de todos los recursos estáticos en un único punto de acceso para el servidor.

Configuración básica

  1. Ubicación de los ficheros. Por defecto, staticfiles busca dentro de cada app que esté en INSTALLED_APPS una sub-carpeta llamada static/. También puedes añadir rutas extra con STATICFILES_DIRS y cambiar la estrategia de búsqueda mediante STATICFILES_FINDERS.
  2. Activar la aplicación. Asegúrate de que django.contrib.staticfiles esté en INSTALLED_APPS. La URL pública por defecto comenzará con /static/ (STATIC_URL).
  3. En las plantillas utiliza la variable STATIC_URL: ```
    
    

Pasos para producción

  1. Define STATIC_URL con la ruta pública definitiva (p. ej. https://cdn.miapp.com/static/).
  2. Indica el destino físico con STATIC_ROOT: ``` STATIC_ROOT = '/var/www/miapp/static'
  3. Ejecuta el recolector: ``` python manage.py collectstatic
    
    Esto copiará todos los ficheros estáticos al directorio anterior.
    
  4. Configura tu servidor web para que sirva el contendio de STATIC_ROOT en la URL definida en STATIC_URL.

Referenciar recursos en plantillas sin rutas absolutas

Introducir URLs absolutas en los templates dificulta los cambios futuros. La solución pasa por usar STATIC_URL o la etiqueta {% static %}.

Mediante context processor

Si django.core.context_processors.static está en TEMPLATE_CONTEXT_PROCESSORS (lo está por defecto) puedes escribir:

<link rel="stylesheet" href="{{ STATIC_URL }}css/main.css">

Recuerda pasar RequestContext a la plantilla o usar un render genérico.

Mediante la etiqueta {% static %}

{% load static %}
<img src="{% static 'img/logo.png' %}">
<script src="{% static ruta_js_dinamica %}"></script>

Servir ficheros estáticos durante el desarrollo

El comando runserver activa automáticamente una vista auxiliar que sirve los recursos cuando DEBUG=True. Si utilizas otro servidor local, añade en urls.py:

from django.contrib.staticfiles.urls import staticfiles_urlpatterns

urlpatterns += staticfiles_urlpatterns()

Esta línea solo funciona con DEBUG=True y STATIC_URL distinto de una URL absoluta.

Servir carpetas adicionales

Para ficheros subidos por usuarios (por ejemplo, MEDIA_ROOT) puedes usar la vista serve:

from django.conf import settings
from django.views.static import serve

if settings.DEBUG:
    from django.conf.urls import url
    urlpatterns += [
        url(r'^media/(?P<path>.*)$', serve, {
            'document_root': settings.MEDIA_ROOT,
        }),
    ]

O de forma más concisa:

from django.conf.urls.static import static

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Despliegue en producción

El flujo habitual consiste en:

  1. Ejecutar collectstatic.
  2. Copiar o sincronizar STATIC_ROOT al servidor que servirá los ficheros estáticos.

Mismo servidor que Django

Tras ejecutar collectstatic en el servidor, apunta tu servidor web (Apache, Nginx…) a la carpeta resutlante.

Servidor independiente

La mayoría de sitios grandes separan la carga de contenido estático en un servidor dedicado (Nginx, lighttpd, etc.). El proceso suele automatizarse con herramientas como Fabric:

from fabric.api import *

env.hosts = ['static.miapp.com']
env.local_static = '/tmp/static'
env.remote_static = '/var/www/static'

def publicar():
    local('python manage.py collectstatic --noinput')
    local('rsync -av --delete {}/ static@{}:{}/'.format(
        env.local_static, env.hosts[0], env.remote_static))

Con esta rutina solo se transfieren los cambios, reduciendo el tiempo de despliegue.

Etiquetas: Django staticfiles collectstatic Nginx Apache

Publicado el 8-15 19:56