2021/02/10
Django モデル データベース FileFieldDjango FileFieldのupload_toでインスタンスIDを使う
バージョン
- Django 3.1.5
- Python 3.8.4
インスタンスIDを保存先パスに使う
DjangoのFileFieldでは、upload_to
に関数を指定することでファイル保存先のパスを動的に決定することができます。
関数内でinstance.user.id
等を使う場面はよくあると思いますが、それと同じようにinstance.id
を使おうとすると正しくインスタンスIDが取得できません。
関数が呼び出された段階では、インスタンスはまだDBに保存されておらず、IDを持たないからです。
以下のようにすると、instance.id
を使えるようになります。
models.py
class MyModel(models.Model):
file = models.FileField(upload_to=file_upload_path)
def file_upload_path(instance, filename):
"""
'uploads/インスタンスID/ファイル名'を返す
"""
return f"uploads/{instance.id}/{filename}"
def save(self, *args, **kwargs):
if self.id is None:
# アップロードされたファイルを変数に代入しておく
uploaded_file = self.file
# 一旦fileフィールドがNullの状態で保存(→インスタンスIDが割り当てられる)
self.file = None
super().save(*args, **kwargs)
# fileフィールドに値をセット
self.file = uploaded_file
if "force_insert" in kwargs:
kwargs.pop("force_insert")
# この段階ではインスタンスIDが存在するので、_file_upload_path関数でinstance.idが使える
super().save(*args, **kwargs)