ご覧いただきありがとうございます!
領護(りょうご)です。
画像やPDFといったファイルを複数同時にアップロードしたい時ってありますよね?
今回は、DjangoのFormViewを使って、複数のファイルを同時にアップロードできる方法を解説します。
アップロードしたデータを保存するCreateViewでも使えるので是非お試しください!
実行環境
Docker Desktop・・・4.28.0
Python・・・3.12.0
Django・・・5.0.3
forms.pyの作成
複数のファイルをアップロードするフォームクラスをforms.pyに作成します。
from django import forms
# 複数のファイルをアップロードするウィジェットクラスを作成
#(コピペでOK!)
class MultipleFileInput(forms.ClearableFileInput):
allow_multiple_selected = True
# 複数のファイルをアップロードするフィールドクラスを作成
#(コピペでOK!)
class MultipleFileField(forms.FileField):
def __init__(self, *args, **kwargs):
kwargs.setdefault("widget", MultipleFileInput())
super().__init__(*args, **kwargs)
def clean(self, data, initial=None):
single_file_clean = super().clean
if isinstance(data, (list, tuple)):
result = [single_file_clean(d, initial) for d in data]
else:
result = single_file_clean(data, initial)
return result
# 複数のファイルをアップロードするフォームクラスを作成
# (ご自身の使用したいフォームクラスにMultipleFileFieldを追加してください)
class MultipleFileUploadForm(forms.Form):
# 複数のファイルをアップロードするフィールドを作成
files = MultipleFileField(label="複数のファイルを選択")
注意!
MultipleFileInput、MultipleFileFieldは、MultipleFileUploadFormよりも先に作成してください。
MultipleFileInput、MultipleFileField、MultipleFileUploadFormの3つのクラスを作成します。
「MultipleFileInput」「MultipleFileField」は、複数のファイルをアップロードするフィールドを作成しています。
「MultipleFileUploadForm」は、複数のファイルをアップロードするフィールドを使って、フォームクラスを作成しています。
files = MultipleFileField(label="複数のファイルを選択")
作成したMultipleFileFieldを使用すると、複数のファイルをアップロードできます。
Djangoが最初から用意しているCharFieldやTextFieldといったフィールドを自分で作成した感じですね。
ご自身の使用したいフォームクラスにMultipleFileFieldを追加してください。
これで複数のファイルをアップロードするフォームクラスの作成は完了しました。
views.pyの作成
続いてviewクラスを作成します。
今回は、FormViewを使用していますが、CreateViewでも同様に使用できます。
from django.urls import reverse_lazy
from django.views.generic import FormView
from .blog_forms import MultipleFileUploadForm
# 複数のファイルをアップロードするページ
class MultipleFileUploadPage(FormView):
template_name = "blog/upload.html"
form_class = MultipleFileUploadForm
success_url = reverse_lazy("multiple_file_upload")
# アップロードしたファイルの情報を確認する(無くてもOK!)
def form_valid(self, form):
# アップロードしたファイルをリスト型で取得
files = form.cleaned_data["files"]
print("ファイルをアップロードしました!")
print(files)
return super().form_valid(form)
FormViewクラスを継承して、複数のファイルをアップロードするページ「MultipleFileUploadPage」を作成しました。
template_nameには、フォームを表示するhtmlファイルのパスを指定します。(この後、htmlファイルを作成します。)
form_classには、先ほど作成したMultipleFileUploadFormを指定します。
success_urlには、アップロード完了後の遷移ページを指定します。
form_valid関数は、ファイルがアップロードできたか確認するために作成しているので、無くても構いません。
これでviewクラスの作成は完了しました。
urls.pyの作成
URLをurls.pyに設定します。
from django.urls import path
from . import views
urlpatterns = [
# 複数ファイルアップロードページ
path(
"multiple-file-upload/",
views.MultipleFileUploadPage.as_view(),
name="multiple_file_upload",
)
]
ここはご自身の好きなURL名で作成してください。
htmlの作成
画面表示に使用するhtmlファイルを作成します。
<h1>複数ファイルアップロードフォーム</h1>
<!-- 複数のファイルをアップロードするフォームの表示 -->
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group">
{{ form.files.label }}
{{ form.files }}
</div>
<button type="submit">アップロードする</button>
</form>
{{ form.files }}に複数のファイルをアップロードするフォームが表示されます。
ファイルをアップロードするので、formタグにenctype="multipart/form-data"を付けることも忘れずに!
動作確認
以上で作成は完了です!
動作を確認してみます。
ファイル選択のフォームが表示されるのでクリック
複数のファイルを選択
「アップロードする」ボタンをクリック
ファイルをアップロードしました!
[<InMemoryUploadedFile: 1.jpg (image/jpeg)>, <InMemoryUploadedFile: 2.jpg (image/jpeg)>, <InMemoryUploadedFile: 3.jpg (image/jpeg)>]
無事、アップロードが完了すると、バックエンド側で複数のファイルをリスト型で取得できます。
def form_valid(self, form):
# アップロードしたファイルをリスト型で取得
files = form.cleaned_data["files"]
print("ファイルをアップロードしました!")
print(files)
# ここに好きな処理を書いていく
return super().form_valid(form)
あとは、取得したファイルを好きなようにform_valid関数の中で処理してあげてください。
アップロードできるファイルを制限する
アップロードできるファイルを制限したい場合もあると思います。
そんな時は、アップロードを許可したいファイルの拡張子バリデーションを設定します。
# osライブラリをインポート
import os
class MultipleFileUploadForm(forms.Form):
files = MultipleFileField(label="複数のファイルを選択")
# 拡張子バリデーションを追加
def clean_files(self):
files = self.cleaned_data["files"]
for file in files:
extension = os.path.splitext(file.name)[1]
# 限定したい拡張子を指定(↓ 限定したい拡張子に書き換えてください ↓)
if not extension.lower() in [".webp", ".png", ".jpg", ".jpeg"]:
raise forms.ValidationError("画像ファイルを選択してください")
return files
osライブラリをインポートして拡張子バリデーション関数を作成します。
関数名は、「clean_フィールド名」にしてください。
今回の例は、webp、png、jpg、jpegの画像ファイルのみアップロードができるように作成しました。
ご自身で限定したい拡張子に書き換えて使用してください。
最後に
DjangoのFormViewを使って、複数のファイルを同時にアップロードできる方法を解説しました。
FormView以外にも、アップロードしたファイルをモデルに保存できるCreateViewでも使用できます。
是非試してみてくださいね!
参考にさせて頂いたサイト様
https://docs.djangoproject.com/en/5.0/topics/http/file-uploads/