Volver a la wiki

ForgivingManifestStaticFilesStorage — Backend de estáticos hasheados

Identidad

Módulo: core/storage.py (nuevo en v1.45.3)

Tipo: Django storage backend, subclase de whitenoise.storage.CompressedManifestStaticFilesStorage

Propósito: servir estáticos con nombres hasheados (app.a1b2c3d4e5f6.js) para activar caché de 1 año + cache-busting automático en deploy, tolerando errores de post-procesado de CSS de terceros.


Firma pública

class ForgivingManifestStaticFilesStorage(CompressedManifestStaticFilesStorage):
    manifest_strict = False
    
    def post_process(self, paths, dry_run=False, **options):
        # Yields (name, hashed_name, processed) tuples;
        # degrada MissingFileError a False (no reescribir CSS) en vez de abortar

Atributos clave:


Cómo funciona

Phase 1: Build-time (Dockerfile.prod, collectstatic)

  1. Django ejecuta manage.py collectstatic --noinput.
  2. Todas las rutas en STATIC_ROOT (/app/staticfiles/) se copian.
  3. Para cada archivo CSS: se reescribe cada url() interna con su nombre hasheado (p.ej. url(../fonts/oswald.woff2) → url(../fonts/oswald.a1b2c3d4e5f6.woff2)).
  4. Si una url() no resoluble aparece (p.ej. FontAwesome all.min.css referencia fa-v4compatibility.woff2 ausente):
    • Antes (sin override): MissingFileError → collectstatic aborta RC ≠ 0 → Docker falla → no se genera staticfiles.json.
    • Ahora (con override): captura el error, devuelve processed=False (ese CSS se sirve sin reescribir las URLs, pero el build continúa) → staticfiles.json generado, resto de estáticos OK.

Phase 2: Runtime (WhiteNoise)

  1. Django inicia; WhiteNoise se intercepta en la cadena WSGI.
  2. Request a /static/... llega a WhiteNoise con el archivo hasheado (p.ej. /static/fonts/oswald.a1b2c3d4e5f6.woff2).
  3. WhiteNoise detecta el nombre inmutable (tiene hash) → sirve con Cache-Control: max-age=31536000, immutable.
  4. Navegador cachea por 1 año. Cambio en el deploy = nuevo hash = nuevo nombre = nueva descarga (old name sigue en caché vieja, no afecta).

Phase 3: Fallback (manifest_strict = False)


Uso en settings

Producción / Staging (config/settings/production.py)

STORAGES = {
    **STORAGES,
    "staticfiles": {"BACKEND": "core.storage.ForgivingManifestStaticFilesStorage"},
}

Este override aplica solo en producción (porque production.py se importa condicionalmente; ver config/wsgi.py).

Desarrollo / Testing

Hereda CompressedStaticFilesStorage de config/settings/base.py — sin manifest, sin hash, no requiere collectstatic previo.


Tolerancia de errores: el caso FontAwesome

Archivo: templates/... incluye {% static "vendor/fontawesome/all.min.css" %} (comprimido, es el bundle completo de FontAwesome).

Referencia interna: el CSS contiene:

@font-face {
  font-family: "Font Awesome 6 Pro";
  src: url("../webfonts/fa-v4compatibility.woff2") format("woff2");
  ...
}

Status en el árbol:

Sin el override:

> python manage.py collectstatic --noinput
Processing static files...
ERROR: core/storage.py - MissingFileError: ... fa-v4compatibility.woff2 not found
collectstatic aborted (RC ≠ 0)
[Docker build FAIL]

Con el override (processed = False):

> python manage.py collectstatic --noinput
Processing static files...
vendor/fontawesome/all.min.css: could not rewrite urls (missing fa-v4compatibility.woff2), serving as-is
... [resto de estáticos procesados normalmente] ...
Generated staticfiles.json ✓
[Docker build OK]

Impacto en caché y deploy

EscenarioAntesDespués
Deploy nuevo (collectstatic normal)Todos los estáticos siguen en caché 60 sEstáticos con nuevo hash → navegador descarga nuevo, viejo queda en caché vieja
Usuario recarga en < 60 s después de deploy anteriorVe la versión vieja (caché)Sigue viendo vieja (manifest obsoleto en navegador) → recarga fría descarga nueva
Estático corrupto / cambio de contenidoNecesita usuario forzar refresco (Ctrl+Shift+R)Automático con nuevo hash

Conclusión: ForgivingManifestStaticFilesStorage es la pieza clave del cache-busting automático por hash. Sin ella, el manifest no se genera y WhiteNoise sigue sirviendo con max-age=60.


Dependencias


Testing


Véase también

Subir