PythonDBとか資格とかPythonとかの話をつらつらと2018-06-16DjangoのFileFieldのバックエンドを動的に切り替えたい(S3BotoStorageの例)DjangoのモデルにはFileFieldやImageFieldなど、バイナリファイルを扱う属性があります。FileFieldImageFieldこれらに格納されるファイルの保存先を動的に変更する方法を確認しました。FileFieldやImageFieldの動きこれらのフィールドにはファイルを格納することができますが、ファイルがバイナリ化されてバックエンドのDBに格納されるわけではありません。パフォーマンスの観点からsettings.MEDIA_ROOTに指定されたディレクトリ配下にファイルを保存し、MEDIA_ROOTを起点とした相対パスの情報のみをDBに格納するように動きます。保存されるパスは各Fieldのupload_toも考慮されますので実際には以下のようなディレクトリになります。MEDIA_ROOT/upload_to/file_name通常はMEDIA_ROOTはローカルファイルパスを指しており、Djangoが稼働するノードのファイルシステム上に保存されます。S3BotoStorageの場合S3BotoStorageはFileFieldなどで格納されるファイルをS3のBucket上に保存してくれるサードパーティライブラリです。**kwargs)FileFieldのソースはこんな感じになっていて、格納先に関わるのはself.storageとself.upload_toです。いずれもクラスが初期化された時点で確定します。storageを明示していない場合はsettingsで設定したものがdefault_storageとして利用されます。FileFieldがどのようなバックエンドで(S3なのかローカルファイルシステムなのか)どのような場所(バケット名やディレクトリ名)を使用するかが確定し、settingsから読み込まれるのはdjango.setup()が実行されて該当のモデルが初期化されたタイミングです。(厳密には、初期化されてから最初にアクセスされたタイミングで確定しますが面倒なので無視します)これがとういうことかは以下のS3BotoStorageを使用しているコードを例に説明します。モデルのcontentはStorageを明示していないものとします。content=tmp_file,)my_other_model.save()コードだけ見ればmy_other_model.contentはbucket_2に保存されてほしいですが、残念ながらbucket_1に保存されます。bucket_2への変更をしてもすでにMyModel.contentのstorageは確定しているので変更が読み込まれることはありません。移行先のModel定義自体が違うのであればFileField.storageを明示して他のバケットを書けばできますが、今回はやんごとなき事情で同じモデルのまま別のバケットに移行する必要があったのでこれはできませんでした。いうことでどうすればいいのかです。S3BotoStorage(bucket='bucket_2')my_other_model.save()結局、実ファイルへのアクセスが発生するタイミング(read,write)時点でのStorageをもとにファイルアクセスが行われるので、上述の例のようにFileField.storageをまるっと差し替えてやれば意図した結果を得ることができます。まとめ利用ケースがマニアック過ぎて誰の役にたつんだって内容をまとめました。FileFieldのデータをバックエンドのファイル含めて別に移行しなければいけなくなったケースくらいでしか生きない知識ですが、どこかで役に立つことを祈っています。CONTENTを中心にまとめます。embyを導入したISUCON11予選に参加して32位で敗退してきました。8はてなブログをはじめよう!denzowさんは、はてなブログを使っています。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。