Я настраиваю проект Django, который использовал файловую систему сервера для хранения статических файлов приложений ( STATIC_ROOT
) и файлов, загруженных пользователем ( MEDIA_ROOT
).
Теперь мне нужно разместить весь этот контент на Amazon S3, поэтому я создал для этого корзину. Использование django-storages
с boto
серверной памяти, мне удалось загрузить собранные статику в ведро 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'
Затем у меня возникла проблема: MEDIA_ROOT
и STATIC_ROOT
не используются в ведре, поэтому корень корзины содержит как статические файлы, так и загруженные пользователем пути.
Итак, я мог установить:
S3_URL = 'http://s3.amazonaws.com/%s' % AWS_STORAGE_BUCKET_NAME
STATIC_URL = S3_URL + STATIC_ROOT
MEDIA_URL = 'S3_URL + MEDIA_ROOT
И используйте эти настройки в шаблонах, но при сохранении в S3 с помощью файлов django-storages
.
Как это можно сделать?
Благодарность!
django
amazon-s3
django-settings
static-files
django-storage
Армандо Перес Маркес
источник
источник
AWS_STORAGE_BUCKET_NAME
), и он используется при создании экземпляра класса, указанного вSTATICFILES_STORAGE
.Ответы:
Я думаю, что следующее должно работать и быть проще, чем метод Mandx, хотя он очень похож:
Создайте
s3utils.py
файл:from storages.backends.s3boto import S3BotoStorage StaticRootS3BotoStorage = lambda: S3BotoStorage(location='static') MediaRootS3BotoStorage = lambda: S3BotoStorage(location='media')
Тогда в вашем
settings.py
:DEFAULT_FILE_STORAGE = 'myproject.s3utils.MediaRootS3BotoStorage' STATICFILES_STORAGE = 'myproject.s3utils.StaticRootS3BotoStorage'
Другой, но связанный пример (который я действительно тестировал) можно увидеть в двух
example_
файлах здесь .источник
В настоящее время я использую этот код в отдельном
s3utils
модуле: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)
Затем в моем модуле настроек:
DEFAULT_FILE_STORAGE = 'myproyect.s3utils.MediaRootS3BotoStorage' STATICFILES_STORAGE = 'myproyect.s3utils.StaticRootS3BotoStorage'
Мне нужно переопределить
_normalize_name()
частный метод, чтобы использовать «фиксированную» версиюsafe_join()
функции, поскольку исходный код дает мнеSuspiciousOperation
исключения для разрешенных путей.Я отправляю это на рассмотрение, если кто-то сможет дать лучший ответ или улучшить этот, это будет очень кстати.
источник
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
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
И запускаем:
python manage.py collectstatic
источник
storages.py
custom_storages.py
from __future__ import absolute_import
Я думаю, что ответ довольно прост и делается по умолчанию. Это работает для меня на AWS Elastic Beanstalk с Django 1.6.5 и 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']
Ключи AWS передаются из файла конфигурации контейнера, а у меня их нет
STATIC_ROOT
или неSTATIC_URL
задан вообще. Также нет необходимости вs3utils.py
файле. Эти данные обрабатываются системой хранения автоматически. Уловка здесь в том, что мне нужно было правильно и динамически ссылаться на этот неизвестный путь в моих шаблонах. Например:<link rel="icon" href="{% static "img/favicon.ico" %}">
Так я обращаюсь к своему значку, который находится локально (до развертывания) в
~/Projects/my_app/project/my_app/static/img/favicon.ico
.Конечно, у меня есть отдельный
local_settings.py
файл для доступа к этому материалу локально в среде разработки, и в нем есть настройки STATIC и MEDIA. Мне пришлось много экспериментировать и читать, чтобы найти это решение, и оно работает стабильно, без ошибок.Я понимаю, что вам нужно статическое и корневое разделение, и, учитывая, что вы можете предоставить только одно ведро, я хотел бы указать, что этот метод берет все папки в моей локальной среде
~/Projects/my_app/project/my_app/static/
и создает папку в корне корзины (например: S3bucket / img / как в примере выше). Таким образом, вы получаете разделение файлов. Например, у вас может бытьmedia
папка вstatic
папке и доступ к ней через шаблон:{% static "media/" %}
Надеюсь, это поможет. Я пришел сюда в поисках ответа и приложил немало усилий, чтобы найти более простое решение, чем расширение системы хранения. Вместо этого я прочитал документацию о предполагаемом использовании Boto и обнаружил, что многое из того, что мне нужно, было встроено по умолчанию. Ура!
источник
Если вы хотите иметь подпапки даже до носителей или статических разделений, вы можете использовать AWS_LOCATION поверх ответа bradenm. Ссылка: https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#usage
AWS_STORAGE_BUCKET_NAME = 'bucket_name' AWS_LOCATION = 'path1/path2/'
источник