Django-storage'lar ve Amazon S3 ile, ancak statik dosyalar ve medya dosyaları için farklı klasörler içeren bir Django projesi nasıl kurulur?


92

Uygulamaların statik dosyalarını ( STATIC_ROOT) ve kullanıcı tarafından yüklenen dosyaları ( MEDIA_ROOT) depolamak için sunucu dosya sistemini kullanan bir Django projesini yapılandırıyorum .

Şimdi tüm bu içeriği Amazon'un S3'ünde barındırmam gerekiyor, bu yüzden bunun için bir paket oluşturdum. Kullanımı django-storagesile botodepolama arka uç, ben S3 kovaya toplanan statik yükleme başardı:

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'

Ardından bir sorunla karşılaştım: MEDIA_ROOTve STATIC_ROOTpakette kullanılmıyor, dolayısıyla paket kökü hem statik dosyaları hem de kullanıcı tarafından yüklenen yolları içeriyor.

Böylece şunları ayarlayabilirim:

S3_URL = 'http://s3.amazonaws.com/%s' % AWS_STORAGE_BUCKET_NAME
STATIC_URL = S3_URL + STATIC_ROOT
MEDIA_URL = 'S3_URL + MEDIA_ROOT

Ve bu ayarları şablonlarda kullanın, ancak S3'te depolarken statik / medya dosyaları arasında bir ayrım yoktur django-storages.

Bu nasıl yapılabilir?

Teşekkürler!


8
Çünkü paketin adını ( AWS_STORAGE_BUCKET_NAME) belirtmek için yalnızca bir ayar vardır ve içinde belirtilen sınıfın bir örneği STATICFILES_STORAGEbaşlatıldığında kullanılan budur.
Armando Pérez Marqués

Yanıtlar:


126

Aşağıdakilerin işe yaraması gerektiğini düşünüyorum ve çok benzer olmasına rağmen Mandx'in yönteminden daha basit:

Bir s3utils.pydosya oluşturun :

from storages.backends.s3boto import S3BotoStorage

StaticRootS3BotoStorage = lambda: S3BotoStorage(location='static')
MediaRootS3BotoStorage  = lambda: S3BotoStorage(location='media')

Sonra sizin settings.py:

DEFAULT_FILE_STORAGE = 'myproject.s3utils.MediaRootS3BotoStorage'
STATICFILES_STORAGE = 'myproject.s3utils.StaticRootS3BotoStorage'

Bir farklı ancak ilişkili örneği (aslında test ettik) iki görülebilir example_dosyaları burada .


1
Benim versiyonumdan kesinlikle daha basit ve daha iyi. Bunu test etmemiş olmama rağmen bunun da işe yarayacağını düşünüyorum. Teşekkürler! Ayrıca django-s3storage repo'nuzu kontrol ediyorum , eğer proje yalnızca S3 kullanıyorsa çok hafif bir çözüm gibi görünüyor.
Armando Pérez Marqués

1
Ve eğer daha fazla paketlemeyle ilgileniyorsanız , django-s3-klasör-depolamaya göz atın . Az önce buldum, bunun aynı çözüm olup olmadığını ama önceden paketlenmiş olup olmadığını anlayamıyorum.
Armando Pérez Marqués

4
Bu benden çalışmıyor, medya dosyaları s3 paketinin / klasörüne yükleniyor. Görünüşe göre konum ayarına saygı gösterilmiyor. django-storages == 1.1.6, django-uzantıları == 1.1.1, django = 1.4
Nathan Keller

3
Benim için ayrı kovalara sahip olmak daha mantıklıydı ve ayarlar modülümün dışında yapılandırma yapmaktan hoşlanmıyorum, bu yüzden
çözümüm

1
Anladığım kadarıyla bu çözümler işe yaramıyor. Yaklaşım şu olmalı: gist.github.com/defrex/82680e858281d3d3e6e4
defrex

8

Şu anda bu kodu ayrı bir s3utilsmodülde kullanıyorum:

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)

Ardından, ayarlar modülümde:

DEFAULT_FILE_STORAGE = 'myproyect.s3utils.MediaRootS3BotoStorage'
STATICFILES_STORAGE = 'myproyect.s3utils.StaticRootS3BotoStorage'

Orijinal kod bana verdiği için _normalize_name(), safe_join()işlevin "sabit" bir sürümünü kullanmak için özel yöntemi yeniden tanımlamam gerekiyorSuspiciousOperation yasal yollar için istisnalar .

Bunu değerlendirmek için gönderiyorum, eğer biri daha iyi bir cevap verebilir veya bunu geliştirebilirse, çok hoş karşılanacaktır.


7

Dosya: 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

Dosya: 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

Ve koş: python manage.py collectstatic


Bu dosyayı storages.pykullanmak custom_storages.pyisteyeceksiniz yerine adlandırırsanızfrom __future__ import absolute_import
Aaron McMillin

2

Cevabın oldukça basit olduğunu ve varsayılan olarak yapıldığını düşünüyorum. Bu, benim için Django 1.6.5 ve Boto 2.28.0 ile AWS Elastic Beanstalk üzerinde çalışıyor:

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 anahtarları kapsayıcı yapılandırma dosyasından aktarılıyor ve bende hiç yok STATIC_ROOTveya hiç STATIC_URLayarlanmamış. Ayrıca s3utils.pydosyaya gerek yok . Bu ayrıntılar, depolama sistemi tarafından otomatik olarak ele alınır. Buradaki hile, şablonlarımda bu bilinmeyen yolu doğru ve dinamik olarak referans göstermem gerektiğidir. Örneğin:

<link rel="icon" href="{% static "img/favicon.ico" %}">

Yerel olarak yaşayan (dağıtım öncesi) faviconuma bu şekilde hitap ediyorum. ~/Projects/my_app/project/my_app/static/img/favicon.ico .

Elbette ayrı bir local_settings.py , dev ortamında bu şeylere yerel olarak erişmek için dosyam var ve STATIC ve MEDIA ayarları var. Bu çözümü bulmak için çok fazla deneme ve okuma yapmak zorunda kaldım ve hiçbir hata olmadan tutarlı bir şekilde çalışıyor.

Statik ve kök ayrımına ihtiyacınız olduğunu anlıyorum ve yalnızca bir kova sağlayabileceğinizi göz önünde bulundurarak, bu yöntemin yerel ~/Projects/my_app/project/my_app/static/ortamımdaki tüm klasörleri altına alıp kova kökünde bir klasör oluşturduğunu belirtmek isterim (örneğin: S3bucket / img / yukarıdaki örnekte olduğu gibi). Böylece dosyaların ayrılmasını elde edersiniz. Örneğin media, staticklasörde bir klasörünüz olabilir ve buna şablon oluşturma yoluyla erişebilirsiniz:

{% static "media/" %}

Umarım bu yardımcı olur. Buraya cevabı aramak için geldim ve depolama sistemini genişletmekten daha basit bir çözüm bulmak için biraz daha zorladım. Bunun yerine, Boto'nun kullanım amacı hakkındaki belgeleri okudum ve ihtiyacım olan şeylerin çoğunun varsayılan olarak yerleşik olduğunu buldum. Şerefe!


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.