ひさふぃの日記

DjangoとPythonとLaravelが好き。大阪でフリーランスエンジニアやってます。

DjangoのImageField・DBによる画像保存について

Djangoのモデルシステム、便利ですよね。

一行書くだけでSQL文を打ち込むことなく、DBを触ることができます。

特にCharFieldやDateTimeFieldは直感的に使えます。

その中で、画像を扱うImageFieldは使用にコツが必要であるため少しハマってしまいました。その時に調べたことをまとめたものになります。

調べる前の私と同じ状況の方に役立つでしょう。

  • ImageFieldの使い方がわからない
  • 画像をDBに保存する仕組みを知らない

画像をDBに保存する仕組み

二種類に分けられるようです。

  • ディレクトリに画像を保存し、ファイルパスをDBに保存
  • 画像をバイナリに変換しDBに保存

通常は上の方法を用いるようです。Djangoの画像アップロードに関して解説されている記事のImageFieldの使い方は、こちら。

フォームで画像をアップロードしてImageFieldに渡すと、特定のディレクトリに画像を保存してpathをDBに保存しているようです。

もう一つの方法は画像をバイナリに変換してDBに保存します。こちらはDBのパフォーマンスが下がる?ようなので非推奨とのことです。

直感的でわかりやすい。ImageFieldで保存する場合は、BytesIO()を呼び出して画像ファイルをバイナリに変換して渡します。

ImageFIeldの使い方

ディレクトリに画像を保存し、ファイルパスをDBに保存する方法を採用します。

まずDjangoのsettings.pyに画像ファイルを保存するディレクトリを教えます。

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

models.pyのImageFieldを宣言する際にも、画像ファイルを保存するディレクトリを指定します。

class Image(models.Model):
    image = models.ImageField(upload_to="image/")

settings.pyで指定したmedia、models.pyで指定したimageを組み合わせた、/project_directory/media/imageに画像が保存されます。

画像をダウンロードして、ImageFieldに保存するファイルパスを返すメソッドを記述します。

class Image_DL():
    def save_and_rename(self, url, name=None):
        res = requests.get(url)
        if res.status_code != 200:
            return "No Image"
        path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))+"/media/image/"
        if name==None:
            path += url.split("/")[-1]
        else:
            path += name
        with open(path, 'wb') as file:
            file.write(res.content)
        return path

このメソッドを呼び出して、ImageFieldに返り値を渡してあげればOKです。

さいごに

画像ファイルがそもそもどのようにDBに保存されているかを知る機会になって良かったです。色々考えられているんですね。すごいな、ほんと。

最後までお読みいただきありがとうございました。それじゃ!

動かして学ぶ!Python Django開発入門