80

アプリの静的ファイル(STATIC_ROOT)とユーザがアップロードしたファイル(MEDIA_ROOT)を格納するためにサーバファイルシステムを使用していたDjangoプロジェクトを設定しています。Djangoプロジェクトをdjango-storageとAmazon S3でセットアップする方法はありますが、静的ファイルとメディアファイルのフォルダは異なりますか?

私は今、Amazon S3のすべてのコンテンツをホストする必要があるので、私はこれのためのバケットを作成しました。 botoストレージバックエンドでdjango-storagesを使用して、私はS3バケットに収集した静をアップロードするために管理:MEDIA_ROOTSTATIC_ROOTは、バケット内で使用されていないので、バケット根元は両方含まれています

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' 

その後、私は問題を抱えて静的ファイルとユーザーがアップロードしたパス。

それでは私が設定できます

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

をテンプレートでこれらの設定を使用しますが、django-storagesとS3に保存するときに、静的/メディアファイルの区別はありません。

これはどのように行うことができますか?

ありがとうございます!

私は現在、分離 s3utilsモジュールでこのコードを使用してい
+2

なぜ2つのバケットがないのですか? –

+8

バケット名(AWS_STORAGE_BUCKET_NAME')を指定する設定は1つだけです。これは、 'STATICFILES_STORAGE'で指定されたクラスのインスタンスがインスタンス化されたときに使用されるものです。 –

答えて

117

私は次は仕事、それは非常に似ていますが、Mandxの方法よりも簡単であるべきだと思う:あなたのsettings.pyに続いて

from storages.backends.s3boto import S3BotoStorage 

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

s3utils.pyファイルを作成します

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

2つのexample_ファイルhereには異なるが関連する例(実際にテストしたもの)があります。

+1

私のバージョンよりはるかに簡単で優れています。私はこれをテストしていませんが、これもうまくいくと思います。ありがとう!私はあなたの[django-s3storage](https://github.com/mstarinc/django-s3storage/)リポジトリもチェックしていますが、S3が排他的にプロジェクトを使用している場合、非常に軽量な解決策です。 –

+1

さらに、パッケージ化が進んでいるなら、[django-s3-folder-storage](http://pypi.python.org/pypi/django-s3-folder-storage/)をチェックしてください。私はちょうどそれを見つけました。これがまったく同じソリューションであるかどうかは分かりませんが、あらかじめパッケージ化されています –

+0

'SimpleLazyObject'はなぜインポートされますか? – glarrain

7

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を与えているからです。

誰かがより良い答えを与えることができる、またはこれを改善することができれば、これは非常に歓迎されます。

2

私は答えがとてもシンプルで、デフォルトで行われていると思います。

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_ROOTSTATIC_URLセットを持っていない:これは、Djangoの1.6.5と後のBoto 2.28.0でAWS Elastic Beanstalkでの私のために働いています。また、s3utils.pyファイルは必要ありません。これらの詳細はストレージシステムによって自動的に処理されます。ここでのトリックは、テンプレート内のこの未知のパスを正確かつ動的に参照する必要があることです。例えば:私は~/Projects/my_app/project/my_app/static/img/favicon.icoでローカルに住んでいる私のファビコン(展開前)に対処する方法です

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

私はもちろん、dev環境でローカルにこのようなものにアクセスするための別ファイルlocal_settings.pyを持っています。これにはSTATICとMEDIAの設定があります。私はこのソリューションを見つけるために多くの実験と読書をしなければならず、エラーなく一貫して動作します。

静的なルート分離が必要であることを理解しています.1つのバケットしか提供できないと考えています。私のローカル環境のすべてのフォルダをに置き換え、バケットルートにフォルダを作成します。 :S3bucket/img /上記の例のように)。だからあなたはファイルの分離を取得します。たとえば、あなたはstaticフォルダ内のmediaフォルダを持っている可能性があり、これでテンプレートを経由してアクセス:

{% static "media/" %} 

私はこのことができます願っています。私はここで答えを探しに来て、ストレージシステムを拡張するより簡単な解決策を見つけるのを少し難しくしました。代わりに、私はBotoの意図された使用に関するドキュメントを読んで、私が必要としていた多くのものがデフォルトで組み込まれていることがわかりました。乾杯!

4

ファイル: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 

ファイル: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 

そして実行します。python manage.py collectstatic

+0

このファイルの名前を '' storage 'custom_storages.py'の代わりに' .py'を使用します。あなたは 'from __future__ import absolute_import'を使いたいでしょう。 –

関連する問題