【Django】django-storagesを使用してMediaストレージをDropboxにホストする


投稿日 2022年6月21日 >> 更新日 2023年3月1日

概要

Djangoのカスタムストレージパッケージである「django-storages」を使用してMediaストレージをDropboxにホストしてファイルや画像を保存していきます。

Heroku等にデプロイする際はMediaファイルをどうしたらよいか考えてしまいましたが、django-storagesで「Amazon S3」のストレージサービスをホストするといったWebサイトを見つけ、他にも様々なストレージサービスへのカスタマイズが可能だったので、Dropboxで試しました。

DropboxをPythonで使用する場合はアカウントを取得し、開発用アプリを作成します。開発用アプリの作成方法は以下の記事で説明しています。

そしてDropbox APIを使用したファイルの書き込みや読み込みは以下の記事で実装しています。

実行環境&使用ライブラリ

実行環境
Windows Subsystem for Linux
Python 3.6.9
pip 21.3.1
使用ライブラリ ライセンス
Django==3.2.10 BSD
django-cleanup==6.0.0 MIT
django-storages==1.12.3 BSD
dropbox==11.32.0 MIT

django-storagesでDropboxストレージサービスを使用するには、以下のバージョンまでが問題無く実行できました。

注意

django==3.2.11以上で「django-storages」のDropboxを設定すると以下のようなエラーが発生するので注意してください。

  • 「SuspiciousFileOperation at /admin/アプリ名/post/add/
    Detected path traversal attempt in '/media/file/ファイル'」
$ pip install django==3.2.10
$ pip install django-cleanup django-storages dropbox

django-storages(Dropbox)の設定

「django-storages」ではDropboxの他に以下のようなストレージサービスをホストすることができます。

  • Amazon S3
  • Apache Libcloud
  • Azure Storage
  • Digital Ocean
  • Dropbox
  • FTP
  • Google Cloud Storage
  • SFTP

完全なドキュメントは以下にあります。

「django-storages」を設定する前のDjangoプロジェクト下での「settings.py」では以下のように設定しています。

DEBUGが「True」の場合はプロジェクト直下のmediaディレクトリにファイルが保管されていきます。

# project/settings.py

from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
...

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

...

# Media files

MEDIA_URL = '/media/'

MEDIA_ROOT = BASE_DIR / 'media'

開発環境(ローカル)の設定

ドキュメント通りに設定すると以下のようになります。

補足

Mediaファイルより下のスペースに「django-storages」の設定をします。INSTALLED_APPSには「django-cleanup」ライブラリしか設定していません。他のサイトでは「storages」と設定されているのを見かけましたが未設定でも機能します。

# project/settings.py

...

INSTALLED_APPS = [
    ...
    'django_cleanup.apps.CleanupConfig', # アップロードされたファイルのURLが削除された時に本体も自動で削除される。
    'apps',
]

...
# Media files

MEDIA_URL = '/media/'

MEDIA_ROOT = BASE_DIR / 'media'

...

# django-storages by Dropbox

DEFAULT_FILE_STORAGE = 'storages.backends.dropbox.DropBoxStorage'
# アクセストークンは開発環境のみハードコード
DROPBOX_OAUTH2_TOKEN = 'MY TOKEN'

DROPBOX_ROOT_PATH = '/media/'

アクセストークンの使用期限は4時間なので注意しましょう。これで完了なので、Djangoを起動して管理画面からファイルをアップロードします。

変更ページにアクセスし、ホスト側のリンクを確認してみます。

今度はDropboxのアカウントにてファイルがアップロードされているか確認します。

「dev-appfolder」というフォルダ名はDropboxの開発用アプリ名です。開発用アプリのタイプによって扱えるフォルダの範囲が異なり、私が作成した開発用アプリでは「App folder」というタイプになるので「/アプリ/開発用アプリ名」というフォルダが自動的に作成された上での操作が可能となっています。

本番環境(リモート)の設定

開発環境でメディアファイルを扱う場合はDjangoプロジェクト直下のMediaディレクトリにファイルが保管されていきますが、本番環境ではアプリ本体の負荷を減らすために別のルートから読み込まれるように切り離して配置します。

なので、Heroku等にデプロイするときだけ「django-storages」が機能するように設定していきます。

まずはDjangoプロジェクトの設定ファイル編集します。

# project/settings.py

...

SECRET_KEY = ''

DEBUG = False

...
# Media files

MEDIA_URL = '/media/'

MEDIA_ROOT = BASE_DIR / 'media'

...

try:
    # ローカルサーバーでの起動で必要な変数
    # プロジェクト直下のsecret_keyを読み込む
    with open(BASE_DIR/'secret_key', 'rb') as key:
        secret_key = key.read()
        SECRET_KEY = secret_key
        DEBUG = True
except:
    pass

if not DEBUG:
    import os

    # リモートサーバーの環境変数からDjangoのシークレットキー取得
    SECRET_KEY = os.environ['SECRET_KEY']

    # django-storages by Dropbox
    DEFAULT_FILE_STORAGE = 'storages.backends.dropbox.DropBoxStorage'
    # リモートサーバーの環境変数からアクセストークンを取得
    DROPBOX_OAUTH2_TOKEN = os.environ['DROPBOX_TOKEN']
    DROPBOX_ROOT_PATH = '/media/'

上から順に説明していくと、DEBUGは基本的に「False」に設定しておりプロジェクト直下に「secret_key」が有るか無いかでDEBUGの切り替えを行います。

secret_keyは設定ファイル内上部にある「SECRET_KEY」の事であり、セキュリティ的に隠す必要があるため別ファイルとしてプロジェクト直下に配置しています。そのため、本番環境下では「SECRET_KEY」をサーバーの環境変数に設定するのでディレクトリに配置している「secret_key」は除外する必要があります。

もしプロジェクト直下に「secret_key」が存在していなければDEBUGは「False」のままとなり「django-storages」が機能します。osモジュールのenvironでリモートサーバーの環境変数に設定している「SECRET_KEY・DROPBOX_TOKEN」から値を取得し「SECRET_KEY・DROPBOX_OAUTH2_TOKEN」変数に代入します。

Linuxサーバーで環境変数の設定をする場合は「export」コマンドで一時的に設定するか、Bashファイルにハードコードするかです。「export」コマンドで設定された環境変数はシステムが停止すると消えてしまいます。Bashファイルに書き込むとそのファイルを更新するだけで永続的に設定できます。

一時的に設定する場合。

$ export DROPBOX_TOKEN=アクセストークン

Bashファイルに書き込む場合は、「vi」エディーでホームディレクトリにある「.bash_profile」を開きます。

$ vi ~/.bash_profile

すると以下のよう内容になっていると思うので、if文より上に「export」コマンドを設定しておきます。

export SECRET_KEY=Djangoのシークレットキー
export DROPBOX_TOKEN=アクセストークン

if [[ -f ~/.bashrc ]] ; then
        . ~/.bashrc
fi

システムが起動すると上記のスクリプトファイルが実行されるようになっているので「env」コマンドで環境変数を確認してみます。

$ env
...
SECRET_KEY=Djangoのシークレットキー
DROPBOX_TOKEN=アクセストークン
...

Herokuサーバーに環境変数を設定するには以下のように設定します。

$ heroku config:set DROPBOX_TOKEN=アクセストークン

ユーザーが設定したHerokuサーバー内の環境変数を確認してみます。

$ heroku config
...
DROPBOX_TOKEN: アクセストークン
SECRET_KEY: Djangoのシークレットキー
...

Dropboxのアクセストークンの使用期限は4時間となっており随時更新が必要です。

アクセストークンの更新については以下の記事で実装しているので宜しければご参照してみてください。

それでは以上となります。

最後までご覧いただきありがとうございました。