Django、静的ファイル、メディアファイルをAWS S3で管理

Twitterでシェア FaceBookでシェア はてなブックマークでシェア

Python - Django
2018年11月22日21:33に更新(約19日前)
2018年10月16日4:31に作成(約56日前)

旧ブログ移行記事です。

概要

CentOS7でDjangoを動かすシリーズシリーズの一つです。 今回はAmazon S3を使って静的ファイルを配信していきます。

Amazon S3側の操作

まずですが、IAMの画面に移動し、「ユーザーを追加」ボタンを押します。 IAMの画面

ユーザー名を入れ、「プログラムによるアクセス」にチェックを入れます。そして、「次のステップ:アクセス権限」を押します。 ユーザー名等の入力

「グループの作成」ボタンを押します。 グループの作成

グループ名を入れて、真ん中の入力欄にS3Full のように入力して絞り込みします。出てきた「AmazonS3FullAccess」にチェックを入れて、「グループの作成」 S3Fullの絞り込み

今作ったグループが表示されるので、チェックを入れて「次のステップ:確認」 次のステップ確認を押す

確認画面になるので、気が済んだら「ユーザーの作成」 確認画面に映る

アクセスキーと、シークレットアクセスキーをメモしておきます。終わったら、右下の「閉じる」ボタンです。 シークレットアクセスキーとアクセスキーをメモ

S3のページに行き、「バケットを作成」ボタンを押します。 バケットを作成ボタンを押す

バケットの設定です。バケット名には、ドットを含めないようにしましょう。それ以外は、通常のURLに使うような文字列で作成します。 バケットの設定画面

次へを押していき、この画面で「このバケットにパブリック読み取りアクセス権限を付与する」を選択し、次へ、そしてバケットを作成します。 バケットを作成する

Django側の操作

ここまで来たら、次は使用しているDjangoプロジェクトに移動します。

sudo pip3.7 install django-storages
sudo pip3/7 install boto3

settings.pyのINSTALLED_APPSに追加

INSTALLED_APPS = [
...
...
    'storages',
]

settings.pyの一番下に、以下を追加します。

# 共通の設定
AWS_ACCESS_KEY_ID = 'メモしたアクセスキー'
AWS_SECRET_ACCESS_KEY = 'メモしたシークレットアクセスキー'
AWS_STORAGE_BUCKET_NAME = 'narito-blog'
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
AWS_S3_OBJECT_PARAMETERS = {
    'CacheControl': 'max-age=86400',  # 1日はそのキャッシュを使う
}


# 静的ファイルの設定
AWS_LOCATION = 'static'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATIC_URL = "https://%s/%s/" % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)


# メディアファイルの設定。今回は「project」というプロジェクト名の例
DEFAULT_FILE_STORAGE = 'project.backends.MediaStorage'

以下の2つの理由により、静的ファイルとメディアファイルは、それぞれ別のストレージクラスを使うことにしました。

  1. /staticと/media、別々のURLとして配信したい
  2. 静的ファイルとメディアファイルで、同名ファイルがあった際の挙動を変えたい

2番目ですが、Djangoデフォルトのファイルアップロードの仕組みとして、同名ファイルが既にあれば違う名前を適当に作成してくれます。1.pngを何回もアップロードすると、1_EWFWEF.pngみたいにリネームしてくれますね。しかしS3Boto3Storageのデフォルトは、同名ファイルを上書きしてしまいます。cssやjsファイルであればこの挙動は問題ありませんが、メディアファイルだとちょっと怖いですね。

静的ファイルのストレージクラスは、STATICFILES_STORAGEで指定します。django-storagesに用意されているS3Boto3Storageを使います。S3Boto3Storageは、settings.pyに書いた各種変数を内部で参照します。AWS_LOCATION = 'static'としているので、S3Boto3Storageクラスは/static というURLで管理することになります。「この定数いらなくね?」と思っても消さないほうが最初は無難です。

# 静的ファイルの設定
AWS_LOCATION = 'static'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATIC_URL = "https://%s/%s/" % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)

メディアファイルはDEFAULT_FILE_STORAGEで指定しますが、静的ファイルと別のストレージクラスを使いたいので、project.backends.MediaStorageとしています。カスタムなストレージクラスを使わないなら、ここを静的ファイルと同じstorages.backends.s3boto3.S3Boto3Storageとしましょう。

DEFAULT_FILE_STORAGE = 'project.backends.MediaStorage'

では、今定義したストレージクラスを作りましょう。settings.pyと同じ階層に、backends.pyを作成します。

from storages.backends.s3boto3 import S3Boto3Storage


class MediaStorage(S3Boto3Storage):
    location = 'media'  # /media というURLで配信
    file_overwrite = False  # 同名ファイルは上書きせずに似た名前のファイルに

これで、静的なファイルであればpython manage.py collectstatic でS3にアップロードされるようになり、メディアファイルも自動でアップロードされるようになります。collectstaticは、ローカル環境でも動作するのが魅力ですね。

既にプロジェクト内などにあるメディアファイルは、手作業でS3の画面からアップロードできます。 既にあるファイルを手作業でアップロードする様子

AWS CLI

AWS CLIを使うことで、フォルダ毎でのダウンロード・アップロードが簡単に行なえます。まず、Pythonライブラリをインストールします。

sudo pip3.7 install awscli

その後、初期設定を行います。以下コマンドです。

aws configure

色々と聞かれるので、答えましょう。リージョンですが、アジアパシフィック (東京)はap-northeast-1です。

AWS Access Key ID [None]:アクセスキー
AWS Secret Access Key []:アクセスシークレットキー
Default region name []:ap-northeast-1
Default output format []:JSON

その後は、コマンドで好きに操作できます。

# バケットの全てを、ローカルの「all」フォルダへ
aws s3 cp s3://narito-blog/ all --recursive

# バケットの「media」フォルダ内全てを、ローカルの「local_media」フォルダへ
aws s3 cp s3://narito-blog/media/ local_media --recursive

# ローカルの「local_media」フォルダを、バケットの「media」へアップロード
aws s3 cp local_media s3://narito-blog/media/ --recursive

参考サイト

英語ですが、こちらのサイトの解説がオススメです。 S3とDjangoの解説

料金については、良いQiitaのまとめ記事があります。 S3の料金体系が分かりにくいと聞かれたので纏めた

Twitterでシェア FaceBookでシェア はてなブックマークでシェア

記事にコメントする