DjangoBrothers BLOG ✍️

2021/02/10

このエントリーをはてなブックマークに追加
Django モデル データベース FileField

Django 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)