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に保存されているかを知る機会になって良かったです。色々考えられているんですね。すごいな、ほんと。
最後までお読みいただきありがとうございました。それじゃ!