carga - static css django
¿Cómo configurar un proyecto de Django con django-storage y Amazon S3, pero con diferentes carpetas para archivos estáticos y archivos multimedia? (4)
Archivo: PROJECT_NAME / custom_storages.py
from django.conf import settings
from storages.backends.s3boto import S3BotoStorage
class StaticStorage(S3BotoStorage):
location = settings.STATICFILES_LOCATION
class MediaStorage(S3BotoStorage):
location = settings.MEDIAFILES_LOCATION
Archivo: PROJECT_NAME / settings.py
STATICFILES_LOCATION = ''static''
MEDIAFILES_LOCATION = ''media''
if not DEBUG:
STATICFILES_STORAGE = ''PROJECT_NAME.custom_storages.StaticStorage''
DEFAULT_FILE_STORAGE = ''PROJECT_NAME.custom_storages.MediaStorage''
AWS_ACCESS_KEY_ID = ''KEY_XXXXXXX''
AWS_SECRET_ACCESS_KEY = ''SECRET_XXXXXXXXX''
AWS_STORAGE_BUCKET_NAME = ''BUCKET_NAME''
AWS_HEADERS = {''Cache-Control'': ''max-age=86400'',}
AWS_QUERYSTRING_AUTH = False
Y ejecute: python manage.py collectstatic
Estoy configurando un proyecto de Django que usaba el sistema de archivos del servidor para almacenar los archivos estáticos de las aplicaciones ( STATIC_ROOT
) y los archivos cargados por el usuario ( MEDIA_ROOT
).
Ahora necesito alojar todo ese contenido en el S3 de Amazon, así que he creado un cubo para esto. Utilizando django-storages
storage con el back-end de almacenamiento de boto
, logré subir statics recopilados al bucket S3:
MEDIA_ROOT = ''/media/''
STATIC_ROOT = ''/static/''
DEFAULT_FILE_STORAGE = ''storages.backends.s3boto.S3BotoStorage''
AWS_ACCESS_KEY_ID = ''KEY_ID...''
AWS_SECRET_ACCESS_KEY = ''ACCESS_KEY...''
AWS_STORAGE_BUCKET_NAME = ''bucket-name''
STATICFILES_STORAGE = ''storages.backends.s3boto.S3BotoStorage''
Luego, tengo un problema: el MEDIA_ROOT
y el STATIC_ROOT
no se utilizan dentro del depósito, por lo que la raíz del depósito contiene tanto los archivos estáticos como las rutas cargadas por el usuario.
Entonces podría establecer:
S3_URL = ''http://s3.amazonaws.com/%s'' % AWS_STORAGE_BUCKET_NAME
STATIC_URL = S3_URL + STATIC_ROOT
MEDIA_URL = ''S3_URL + MEDIA_ROOT
Y use esas configuraciones en las plantillas, pero no hay distinción de archivos estáticos / multimedia cuando se almacena en S3 con django-storages
.
¿Cómo se puede hacer esto?
¡Gracias!
Actualmente estoy usando este código en un módulo s3utils
separado:
from django.core.exceptions import SuspiciousOperation
from django.utils.encoding import force_unicode
from storages.backends.s3boto import S3BotoStorage
def safe_join(base, *paths):
"""
A version of django.utils._os.safe_join for S3 paths.
Joins one or more path components to the base path component intelligently.
Returns a normalized version of the final path.
The final path must be located inside of the base path component (otherwise
a ValueError is raised).
Paths outside the base path indicate a possible security sensitive operation.
"""
from urlparse import urljoin
base_path = force_unicode(base)
paths = map(lambda p: force_unicode(p), paths)
final_path = urljoin(base_path + ("/" if not base_path.endswith("/") else ""), *paths)
# Ensure final_path starts with base_path and that the next character after
# the final path is ''/'' (or nothing, in which case final_path must be
# equal to base_path).
base_path_len = len(base_path) - 1
if not final_path.startswith(base_path) /
or final_path[base_path_len:base_path_len + 1] not in ('''', ''/''):
raise ValueError(''the joined path is located outside of the base path''
'' component'')
return final_path
class StaticRootS3BotoStorage(S3BotoStorage):
def __init__(self, *args, **kwargs):
super(StaticRootS3BotoStorage, self).__init__(*args, **kwargs)
self.location = kwargs.get(''location'', '''')
self.location = ''static/'' + self.location.lstrip(''/'')
def _normalize_name(self, name):
try:
return safe_join(self.location, name).lstrip(''/'')
except ValueError:
raise SuspiciousOperation("Attempted access to ''%s'' denied." % name)
class MediaRootS3BotoStorage(S3BotoStorage):
def __init__(self, *args, **kwargs):
super(MediaRootS3BotoStorage, self).__init__(*args, **kwargs)
self.location = kwargs.get(''location'', '''')
self.location = ''media/'' + self.location.lstrip(''/'')
def _normalize_name(self, name):
try:
return safe_join(self.location, name).lstrip(''/'')
except ValueError:
raise SuspiciousOperation("Attempted access to ''%s'' denied." % name)
Luego, en mi módulo de configuración:
DEFAULT_FILE_STORAGE = ''myproyect.s3utils.MediaRootS3BotoStorage''
STATICFILES_STORAGE = ''myproyect.s3utils.StaticRootS3BotoStorage''
Tengo que redefinir el método privado _normalize_name()
para usar una versión "fija" de la función safe_join()
, ya que el código original me está dando excepciones de safe_join()
SuspiciousOperation
para rutas legales.
Estoy publicando esto para consideración, si alguien puede dar una mejor respuesta o mejorar esta, será muy bienvenido.
Creo que la respuesta es bastante simple y está hecha por defecto. Esto me funciona en AWS Elastic Beanstalk con Django 1.6.5 y Boto 2.28.0:
STATICFILES_FINDERS = (
''django.contrib.staticfiles.finders.FileSystemFinder'',
''django.contrib.staticfiles.finders.AppDirectoriesFinder'',
)
TEMPLATE_LOADERS = (
''django.template.loaders.filesystem.Loader'',
''django.template.loaders.app_directories.Loader'',
)
DEFAULT_FILE_STORAGE = ''storages.backends.s3boto.S3BotoStorage''
STATICFILES_STORAGE = ''storages.backends.s3boto.S3BotoStorage''
AWS_ACCESS_KEY_ID = os.environ[''AWS_ACCESS_KEY_ID'']
AWS_SECRET_ACCESS_KEY = os.environ[''AWS_SECRET_KEY'']
Las claves AWS se transfieren desde el archivo de configuración del contenedor y no tengo STATIC_ROOT
ningún STATIC_ROOT
o STATIC_URL
. Además, no es necesario el archivo s3utils.py
. Estos detalles son manejados por el sistema de almacenamiento de forma automática. El truco aquí es que necesitaba hacer referencia a esta ruta desconocida en mis plantillas de forma correcta y dinámica. Por ejemplo:
<link rel="icon" href="{% static "img/favicon.ico" %}">
Así es como me dirijo a mi favicon que vive localmente (previo al despliegue) en ~/Projects/my_app/project/my_app/static/img/favicon.ico
.
Por supuesto, tengo un archivo local_settings.py
separado para acceder a este material localmente en el entorno de desarrollo y tiene las configuraciones ESTÁTICA y MEDIA. Tuve que experimentar y leer mucho para encontrar esta solución y funciona de manera consistente sin errores.
Entiendo que necesita la separación estática y de raíz, y teniendo en cuenta que solo puede proporcionar un depósito, señalaría que este método toma todas las carpetas de mi entorno local en ~/Projects/my_app/project/my_app/static/
y crea un carpeta en la raíz del contenedor (es decir: S3bucket / img / como en el ejemplo anterior). Entonces consigues separación de archivos. Por ejemplo, podría tener una carpeta de media
en la carpeta static
y acceder a ella a través de plantillas con esto:
{% static "media/" %}
Espero que esto ayude. Vine aquí buscando la respuesta y presioné un poco más para encontrar una solución más simple que extender el sistema de almacenamiento. En su lugar, leí la documentación sobre el uso previsto de Boto y descubrí que gran parte de lo que necesitaba estaba incorporado de manera predeterminada. ¡Aclamaciones!
Creo que lo siguiente debería funcionar y ser más simple que el método de Mandx, aunque es muy similar:
Crea un archivo s3utils.py
:
from storages.backends.s3boto import S3BotoStorage
StaticRootS3BotoStorage = lambda: S3BotoStorage(location=''static'')
MediaRootS3BotoStorage = lambda: S3BotoStorage(location=''media'')
Luego en su settings.py
:
DEFAULT_FILE_STORAGE = ''myproject.s3utils.MediaRootS3BotoStorage''
STATICFILES_STORAGE = ''myproject.s3utils.StaticRootS3BotoStorage''
Un ejemplo diferente pero relacionado (que en realidad he probado) se puede ver en los dos archivos example_
here .