Nuxt&Django REST FrameworkでS3を使ってメディアを保存する

# 前提

画像ファイルや映像ファイルといったメディアを直接DBに保存するのはSQLのパフォーマンス的に現実的に考えるとなかなかあり得ることではありません。

やはり[S3](https://aws.amazon.com/jp/s3/)のようなストレージサービスに預けてそのパスをDRFで読み込み→クライアントサイドで出力が一般的でしょう。

なので今回はNuxtで画像を伴ったデータを追加し、それらがきちんと出力されるまでの流れを書いていきます。

なお、既にDjangoのプロジェクト、AWSのアカウントは所持しているものとします。

私は[ここ](https://github.com/Kuehar/nuxt-django)からダウンロードしたコードの設定ファイルを変えて実装しています。


# 環境

boto3==1.13.25
botocore==1.16.25
Django==3.0.7
django-cors-headers==3.2.1
django-storages==1.9.1
djangorestframework==3.11.0

# 導入

## IAM

まずはIAMにアクセスしてS3にアクセスができるようなユーザーを作っておきましょう。
AWSのマネジメントコンソールにアクセスした際に出てくる検索バーに`IAM`と打ち込み、IAMのページにアクセスしてください。

![スクリーンショット 2020-06-12 14.32.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/c4ce9f32-a9f2-c3ab-04f9-fdc2d27046c8.png)

そこでユーザーのページからユーザーを追加するというというページにとび、そこで任意のユーザー名、プログラムによるアクセスにチェックを入れてアクセス権限のページへと進んでください。

![スクリーンショット 2020-06-12 14.36.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/17dd656c-893a-96f5-c996-3761876c3427.png)

そこでユーザーをグループに追加を選び、その上で任意のグループ名、そして権限として`AmazonS3FullAccess`のポリシーを割り当てます。

![スクリーンショット 2020-06-12 14.40.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/35a1b044-e2d5-fb76-6eb0-64c5e3eded79.png)

![スクリーンショット 2020-06-12 14.39.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/9e08c34e-d6cf-1f3d-4bb8-72f5cc8f7a29.png)

これで次のタグの追加（オプション）に進みますが、ここは無視して確認に進んで大丈夫です。

すると新しく追加された場合、ユーザー名とアクセスキー、そしてシークレットアクセスキーが表示されます。

こちらはあとで使いますので覚えておいてください。
ここまででIAMに関する部分は終わりです。

## S3

次にS3でデータの保存先となるバケットを作成しましょう。

![スクリーンショット 2020-06-09 12.06.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/7380c752-74f6-c64a-51ad-341942731a59.png)

[S3](https://aws.amazon.com/jp/s3/)にアクセスし、バケットを作成します。

![スクリーンショット 2020-06-12 15.59.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/f7230417-df27-2387-7ce7-50b53d3c63dc.png)

今回はひとまずこういった設定にしました。
パブリックアクセスをオフにして、残りの設定はひとまず無視してこのまま作成して大丈夫です。

ここまででひとまずS3の初期設定は終わりです。

## Django

DjangoでS3にファイルを保存するために、

- [django-storages
](https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html)

- [Boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/index.html)

をインストールします。

```
$ pip install boto3 django-storages
```

>Settings
To upload your media files to S3 set:

>DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
To allow django-admin.py collectstatic to automatically put your static files in your bucket set the following in your settings.py:

>STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

>AWS_ACCESS_KEY_ID
Your Amazon Web Services access key, as a string.
AWS_SECRET_ACCESS_KEY
Your Amazon Web Services secret access key, as a string.

>Note

>If AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are not set, boto3 internally looks up IAM credentials.

>AWS_STORAGE_BUCKET_NAME
Your Amazon Web Services storage bucket name, as a string.

どうやらドキュメントをみたところ、以下が必須なようです。

```Python:settings.py
# Django-Storage
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
STATICFILES_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

# AWS-Settings
AWS_ACCESS_KEY_ID = 'YOUR_AWS_ACCESS_KEY_ID'
AWS_SECRET_ACCESS_KEY = 'YOUR_AWS_SECRET_ACCESS_KEY'
AWS_STORAGE_BUCKET_NAME = 'nuxt-django'
AWS_LOCATION = 'static' # s3バケット上のベースとなるファイルパス

# STATIC-Files
AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
STATIC_URL = 'https://%s/%s/' % (AWS_S3_CUSTOM_DOMAIN, AWS_LOCATION)
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]
```

こんな感じで設定しておいてください。

この後に

```
$ python manage.py collectstatic
```

を行うと・・・

```
164 static files copied.
```

といったようなメッセージが返ってきます。

実際にS3のバケットを見てみましょう。

![スクリーンショット 2020-06-12 16.46.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/feb35468-a514-6218-ef4b-d9dc0a8a06da.png)

実際にstaticというフォルダ名で保存されていますね。
ここまででひとまずDjangoの設定は終わりました。

## DRFの設定

これが必要かと思いきや実は冒頭のソースをそのまま使った場合ここまでの設定だけで終わりです。
なので今後Nuxt側でAPIを叩いたらメディアファイルは自動的にS3にアップロードされます。

例えば、こういう風に、クライアントサイドから画像を伴ったPOSTを受けると・・・

![スクリーンショット 2020-06-12 17.25.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/7a9057ed-de27-0d9b-252a-5a169ba0f107.png)

![スクリーンショット 2020-06-12 17.28.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/74423f27-b8cb-d14c-87b1-a5aaf7a26054.png)

![スクリーンショット 2020-06-12 17.28.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/412789/5b2cd662-208b-9892-06f8-e3b3cf032c76.png)

こんな感じにアップロードされています。

ここまででひとまずメディアを保存することに成功したのでここで終わります。
お疲れ様でした。

この記事が誰かの役に立てば幸いです。