variable template examples python django django-staticfiles

python - template - Versiones estáticas de django



django template variable (9)

¿Es tan malo reinventar la rueda y crear una implementación propia? Además, me gustaría que el código de bajo nivel (nginx por ejemplo) sirva mis archivos estáticos en producción en lugar de la aplicación Python, incluso con backend. Y una cosa más: me gustaría que los enlaces permanezcan igual después del nuevo cálculo, por lo que el navegador solo busca archivos nuevos. Así que here''s punto de vista mío:

template.html:

{% load md5url %} <script src="{% md5url "example.js" %}"/>

fuera de html:

static/example.js?v=5e52bfd3

settings.py:

STATIC_URL = ''/static/'' STATIC_ROOT = os.path.join(PROJECT_DIR, ''static'')

appname / templatetags / md5url.py:

import hashlib import threading from os import path from django import template from django.conf import settings register = template.Library() class UrlCache(object): _md5_sum = {} _lock = threading.Lock() @classmethod def get_md5(cls, file): try: return cls._md5_sum[file] except KeyError: with cls._lock: try: md5 = cls.calc_md5(path.join(settings.STATIC_ROOT, file))[:8] value = ''%s%s?v=%s'' % (settings.STATIC_URL, file, md5) except IsADirectoryError: value = settings.STATIC_URL + file cls._md5_sum[file] = value return value @classmethod def calc_md5(cls, file_path): with open(file_path, ''rb'') as fh: m = hashlib.md5() while True: data = fh.read(8192) if not data: break m.update(data) return m.hexdigest() @register.simple_tag def md5url(model_object): return UrlCache.get_md5(model_object)

Tenga en cuenta que para aplicar los cambios se debe reiniciar una aplicación uwsgi (para ser un proceso específico).

Estoy trabajando en alguna solución universal para problemas con archivos estáticos y actualizaciones en ella.

Ejemplo: digamos que hubo un sitio con el archivo /static/styles.css (y el sitio se usó durante mucho tiempo), por lo que muchos visitantes almacenaron este archivo en el caché.

Ahora estamos haciendo cambios en este archivo css y actualizamos en el servidor, pero algunos usuarios aún tienen una versión anterior (a pesar de la fecha de modificación devuelta por el servidor)

La solución obvia: agregue alguna versión al archivo /static/styles.css?v=1.1

pero en este caso, el desarrollador debe realizar un seguimiento de los cambios en este archivo e incrementar manualmente la versión

Solución 2: cuente el hash md5 del archivo y añádalo a la url /static/styels.css/?v={mdp5hashvalue}

que se ve mucho mejor, pero md5 debe calcularse de forma automática ...

Es posible que yo lo vea - crear una etiqueta de plantilla como esta

{% static_file "style.css" %}

el cual hará

<link src="/static/style.css?v=md5hash">

PERO, no quiero que esta etiqueta calcule md5 en cada carga de página, y no quiero almacenar el hash en django-cache, porque luego tendremos que borrar después de actualizar el archivo ...

Alguna idea ?


¿Qué tal si siempre tiene un Parámetro de URL en su URL con una versión y cada vez que tiene una versión importante, cambia la versión en su Parámetro de URL? Incluso en el DNS. Entonces, si www.yourwebsite.com carga www.yourwebsite.com/index.html?version=1.0 , luego del lanzamiento principal, el navegador debería cargar www.yourwebsite.com/index.html?version=2.0

Supongo que esto es similar a su solución 1. En lugar de rastrear archivos, ¿puede rastrear directorios completos? Por ejemplo, ratehr que /static/style/css?v=2.0 puede hacer /static-2/style/css o incluso hacerlo granular /static/style/cssv2/ .


Django 1.4 ahora incluye CachedStaticFilesStorage que hace exactamente lo que necesita (bueno ... casi ).

Lo usas con la tarea manage.py collectstatic . Todos los archivos estáticos se recopilan de sus aplicaciones, como de costumbre, pero este administrador de almacenamiento también crea una copia de cada archivo con el hash MD5 añadido al nombre. Entonces, por ejemplo, digamos que tiene un archivo css/styles.css , también creará algo como css/styles.55e7cbb9ba48.css .

Por supuesto, como mencionó, el problema es que no desea que sus vistas y plantillas calculen el hash MD5 todo el tiempo para encontrar las URL adecuadas para generar. La solución es el almacenamiento en caché. Ok, pediste una solución sin almacenamiento en caché, lo siento, por eso dije casi . Pero no hay razón para rechazar el almacenamiento en caché, realmente. CachedStaticFilesStorage utiliza un caché específico llamado staticfiles . Por defecto, utilizará su sistema de caché existente, y voilà! Pero si no desea que use su caché regular, tal vez porque es un memcache distribuido y desea evitar la sobrecarga de las consultas de red solo para obtener nombres de archivos estáticos, entonces puede configurar un caché de RAM específico solo para staticfiles . Es más fácil de lo que parece: echa un vistazo a esta excelente publicación de blog . Así es como se vería:

CACHES = { ''default'': { ''BACKEND'': ''django.core.cache.backends.memcached.PyLibMCCache'', ''LOCATION'': ''127.0.0.1:11211'', }, ''staticfiles'': { ''BACKEND'': ''django.core.cache.backends.locmem.LocMemCache'', ''LOCATION'': ''staticfiles-filehashes'' } }


Hay una actualización para el código @ deathangel908. Ahora funciona bien con el almacenamiento S3 también (y creo que con cualquier otro almacenamiento). La diferencia es el uso del almacenamiento de archivos estáticos para obtener el contenido del archivo. Original no funciona en S3.

appname / templatetags / md5url.py:

import hashlib import threading from django import template from django.conf import settings from django.contrib.staticfiles.storage import staticfiles_storage register = template.Library() class UrlCache(object): _md5_sum = {} _lock = threading.Lock() @classmethod def get_md5(cls, file): try: return cls._md5_sum[file] except KeyError: with cls._lock: try: md5 = cls.calc_md5(file)[:8] value = ''%s%s?v=%s'' % (settings.STATIC_URL, file, md5) except OSError: value = settings.STATIC_URL + file cls._md5_sum[file] = value return value @classmethod def calc_md5(cls, file_path): with staticfiles_storage.open(file_path, ''rb'') as fh: m = hashlib.md5() while True: data = fh.read(8192) if not data: break m.update(data) return m.hexdigest() @register.simple_tag def md5url(model_object): return UrlCache.get_md5(model_object)


La principal ventaja de esta solución: no tiene que modificar nada en las plantillas.

Esto agregará la versión de compilación en STATIC_URL , y luego el servidor web la eliminará con una regla de Rewrite .

settings.py

# build version, it''s increased with each build VERSION_STAMP = __versionstr__.replace(".", "") # rewrite static url to contain the number STATIC_URL = ''%sversion%s/'' % (STATIC_URL, VERSION_STAMP)

Así que la url final sería, por ejemplo, este:

/static/version010/style.css

Y luego Nginx tiene una regla para volver a escribirla en /static/style.css

location /static { alias /var/www/website/static/; rewrite ^(.*)/version([/.0-9]+)/(.*)$ $1/$3; }


Simple templatetag vstatic que crea archivos URL estáticos versionados que extienden el comportamiento de Django:

from django.conf import settings from django.contrib.staticfiles.templatetags.staticfiles import static @register.simple_tag def vstatic(path): url = static(path) static_version = getattr(settings, ''STATIC_VERSION'', '''') if static_version: url += ''?v='' + static_version return url

Si desea configurar automáticamente STATIC_VERSION al hash de confirmación de git actual, puede usar el siguiente fragmento de código (ajuste del código de Python3 si es necesario):

import subprocess def get_current_commit_hash(): try: return subprocess.check_output([''git'', ''rev-parse'', ''--short'', ''HEAD'']).strip().decode(''utf-8'') except: return ''''

En settings.py llame a get_current_commit_hash() , por lo que esto se calculará solo una vez:

STATIC_VERSION = get_current_commit_hash()


Yo sugeriría usar algo como django-compressor . Además de manejar automáticamente este tipo de cosas por usted, también combinará y reducirá automáticamente sus archivos para una carga rápida de páginas.

Incluso si no terminas usándolo en su totalidad, puedes inspeccionar su código para obtener orientación en la configuración de algo similar. Se ha evaluado mejor que cualquier otra cosa que pueda obtener con una simple respuesta .



Django 1.7 agregó ManifestStaticFilesStorage , una mejor alternativa a CachedStaticFilesStorage que no usa el sistema de caché y resuelve el problema del cálculo del hash en el tiempo de ejecución.

Aquí hay un extracto CachedStaticFilesStorage :

CachedStaticFilesStorage no se recomienda , en casi todos los casos ManifestStaticFilesStorage es una mejor opción. Hay varias penalizaciones de rendimiento cuando se utiliza CachedStaticFilesStorage, ya que una falta de memoria caché requiere archivos hash en tiempo de ejecución. El almacenamiento remoto de archivos requiere varios viajes de ida y vuelta al hash de un archivo en una falta de caché, ya que se requieren varios accesos de archivos para garantizar que el hash de archivo sea correcto en el caso de rutas de archivos anidadas.

Para usarlo, simplemente agregue la siguiente línea a settings.py :

STATICFILES_STORAGE = ''django.contrib.staticfiles.storage.ManifestStaticFilesStorage''

Y luego, ejecute python manage.py collectstatic ; agregará el MD5 al nombre de cada archivo estático.