【Django】画像ファイルをアップロード・表示(配信)する方法(モデル利用)
2021.12.29 /
本記事ではPythonのフレームワークDjangoで、画像ファイルをアップロード・表示する方法について解説していきます。
ここではモデルを利用するため、ImageFieldをフィールドとして持たせます。
アップロードされた画像ファイルを表示(配信)する場合は、本記事で紹介している仕組みを利用します。
モデルを利用せずに画像をサーバーにアップロードする方法については以下記事をご参照ください。
【Django】モデルを使用せずに画像・PDFファイルをサーバーにアップロードする
Pillowのインストール
モデルでImageFieldを使用する場合は、画像処理ライブラリであるPillowをインストールする必要があります。
PillowはPIL(Python Image Library)からフォークされたライブラリであり、Pythonで画像処理を行う際に利用されます。
Pillowのインストールはpipコマンドを利用します。
pip install pillow
mediaフォルダの作成
画像などのファイルを保存するためのフォルダを作成します。
ここではベースフォルダ(manage.pyが置いてあるフォルダ)にmediaフォルダを作成してください。
settings.py:メディア設定追加
画像などのファイルをアップロードおよび表示(配信)するためには、以下に示す条件を満たさなければなりません。
- アップロード先のフォルダを指定
- アップロードしたファイルを表示(公開)するためのパスを指定
上記条件を満たすためにsettings.pyに以下2つの設定を追加します。
設定値 | 説明 |
---|---|
MEDIA_URL | ファイルへのURLを指定 |
MEDIA_ROOT | ファイルのアップロード先フォルダを指定 |
MEDIA_URLはデフォルトで「/media/」が設定されています。基本的にはデフォルトのままでいいです。クライアント側がファイルにアクセスするためのURLを指定しています。
例えばoffice54.pngにアクセスする場合は以下のようなURLになります。
MEDIA_ROOTは開発環境(ローカル環境)と本番環境で設定値が異なります。
開発環境(ローカル環境)では次のようにMEDIA_ROOTを指定します。
MEDIA_ROOT = BASE_DIR / 'media'
本番環境(リバースプロキシで配信)では以下のように設定します。
MEDIA_ROOT = f'/var/www/{BASE_DIR.name}/media'
実際にsettings.pyに書き込むときは、開発環境でも本番環境でも動くように次のようにします。
MEDIA_URL = '/media/'
if DEBUG:
MEDIA_ROOT = BASE_DIR / 'media'
else:
MEDIA_ROOT = f'/var/www/{BASE_DIR.name}/media'
開発環境では「DEBUG = True」、本番環境では「DEBUG = False」になるため上記のようになります。
urls.py:pathの追加
プロジェクト内のurls.pyへ以下を追加します。
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
…
]
# 以下を追加する
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
models.py:ImageFieldを定義
モデルに画像を保存するためのImageFieldを定義します。
以下では例として、モデルUserにプロフィール画像を保存するフィールドprofile_imageを定義しています。
class User(AbstractBaseUser, PermissionsMixin):
…
profile_image = models.ImageField(null=True, blank=True)
ImageFieldのオプション「upload_to」を利用すると、アップロード先のフォルダを動的に変更できます。
新たにフィールドを定義したら、忘れずにマイグレーションファイルの作成およびmigrateを実行してください。
python manage.py makemigrations
python manage.py migrate
forms.py:フォームクラスの作成
画像をアップロードするためのフォームを作成していきます。
Djangoにはフォームを簡単に作成する仕組みが備わっています。Djangoでフォームを利用する方法は以下記事をご参照ください。
【Django】フォームの作成:forms.pyにフォームクラスを定義する(forms.Form)
ここではモデルを利用したフォームを作成します。詳しい方法が知りたい方は以下記事をご参照ください。
【Django】forms.py:モデルを利用したフォームの作成方法(forms.ModelForm)
以下例のようにフォームクラスではModelFormを継承して作成します。
class UserInfoEdit(forms.ModelForm):
class Meta:
model = User
fields = ('email','username','profile_image')
views.py:アップロード時の処理を追記
views.pyに画像がアップロードされたときの処理を以下のように追加します。
以下例ではアカウント情報(プロフィール画像を含む)の変更フォームが送信されたときの処理を記しています。
def account_edit(request, account_id):
account = get_object_or_404(User, pk=account_id)
if request.method == "POST":
form = UserInfoEdit(request.POST, request.FILES, instance=account)
if form.is_valid():
form.save()
messages.add_message(request, messages.SUCCESS, "SUCCESS")
return redirect('account_edit', account_id=account_id)
messages.add_message(request, messages.ERROR, "FAIL")
else:
form = UserInfoEdit(instance=account)
return render(request, 'accounts/account_edit.html', {'form':form})
ここで重要なのが、フォームクラスの引数にrequest.FILESを指定しておくことです。
またフォームクラスの引数によって、データベースへの新規登録なのか更新登録なのかが変わります。詳しくは以下記事をご参照ください。
【Django】フォームForm:データベースへの新規登録・更新機能を組み込む(instance変数)
今回のように情報を更新するような処理の場合、処理が成功したかどうかをユーザーに伝えるのがよいシステムと言えます。
そこで上記例でも利用していますが、通知メッセージ機能(フラッシュメッセージ)を使うことをお勧めします。
Djangoに通知メッセージ機能を追加する方法は以下記事をご参照ください。
【Django】通知メッセージを表示する方法(メッセージフレームワーク)
テンプレート:フォームタグの利用
テンプレートで作成したフォームクラスを利用するためにフォームタグを使用します。
以下例はbootstrap4を利用しています。
<form class="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form %}
{% bootstrap_button button_type="submit" content="Edit" %}
</form>
画像ファイルをformで扱えるように「enctype="multipart/form-data"」を必ず記載しましょう
このようにコードを書くことで、Djangoでは簡単に下図のようなフォームが簡単に作成できます。
テンプレート:画像の表示
アップロードされた画像を表示する実装例を以下に記します。
ここではユーザーアカウントのプロフィール画像が存在する場合に画像を表示するコードになります。
{% if user.profile_image %}
<li class="nav-item"><img src="{{ user.profile_image.url }}" alt=""></li>
{% endif %}
プロフィール画像が存在する場合に、「user.profile_image」に対して「url」属性で画像が配信されるURLが取得できます。
まとめ
本記事「【Django】画像ファイルをアップロード・表示(配信)する方法(モデル利用)」はいかがでしたか。
Djangoにアップロード機能は簡単に追加できます。本記事を参考にして、Webアプリケーションにアップロード機能を実装してみてください。