ブログBLOG

\ Web・ゲーム開発に関する情報を発信中 /

【Django】複数のファイルを同時にアップロードできるフォームの作り方

Django
django , python
20240317_django-formview-multiple-file-upload

ご覧いただきありがとうございます!
領護(りょうご)です。

ファイルを複数アップロードする説明画像
画像やPDFといったファイルを複数同時にアップロードしたい時ってありますよね?
今回は、DjangoのFormViewを使って、複数のファイルを同時にアップロードできる方法を解説します。
アップロードしたデータを保存するCreateViewでも使えるので是非お試しください!

目次

実行環境

Docker Desktop・・・4.28.0
Python・・・3.12.0
Django・・・5.0.3

forms.pyの作成

複数のファイルをアップロードするフォームクラスを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よりも先に作成してください。

MultipleFileInputMultipleFileFieldMultipleFileUploadFormの3つのクラスを作成します。
「MultipleFileInput」「MultipleFileField」は、複数のファイルをアップロードするフィールドを作成しています。
「MultipleFileUploadForm」は、複数のファイルをアップロードするフィールドを使って、フォームクラスを作成しています。

forms.py
files = MultipleFileField(label="複数のファイルを選択")

作成したMultipleFileFieldを使用すると、複数のファイルをアップロードできます。
Djangoが最初から用意しているCharFieldやTextFieldといったフィールドを自分で作成した感じですね。
ご自身の使用したいフォームクラスにMultipleFileFieldを追加してください。
これで複数のファイルをアップロードするフォームクラスの作成は完了しました。

views.pyの作成

続いてviewクラスを作成します。
今回は、FormViewを使用していますが、CreateViewでも同様に使用できます。

views.py
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に設定します。

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ファイルを作成します。

blog/upload.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"を付けることも忘れずに!

動作確認

以上で作成は完了です!
動作を確認してみます。

20240317_django-formview-multiple-file-upload-02

ファイル選択のフォームが表示されるのでクリック

20240317_django-formview-multiple-file-upload-03

複数のファイルを選択

20240317_django-formview-multiple-file-upload-04

「アップロードする」ボタンをクリック

ファイルをアップロードしました!
[<InMemoryUploadedFile: 1.jpg (image/jpeg)>, <InMemoryUploadedFile: 2.jpg (image/jpeg)>, <InMemoryUploadedFile: 3.jpg (image/jpeg)>]

無事、アップロードが完了すると、バックエンド側で複数のファイルをリスト型で取得できます。

forms.py
def form_valid(self, form):
    # アップロードしたファイルをリスト型で取得
    files = form.cleaned_data["files"]
    print("ファイルをアップロードしました!")
    print(files)
    # ここに好きな処理を書いていく
    return super().form_valid(form)

あとは、取得したファイルを好きなようにform_valid関数の中で処理してあげてください。

アップロードできるファイルを制限する

アップロードできるファイルを制限したい場合もあると思います。
そんな時は、アップロードを許可したいファイルの拡張子バリデーションを設定します。

forms.py
# 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/


\ よかったらシェアしてね /

関連記事