ファイルのアップロード—Djangoドキュメント

提供:Dev Guides
< DjangoDjango/docs/3.2.x/topics/http/file-uploads
移動先:案内検索

ファイルのアップロード

Djangoがファイルのアップロードを処理すると、ファイルデータは request.FILES に配置されます(requestオブジェクトの詳細については、要求および応答オブジェクトのドキュメントを参照してください)。 。 このドキュメントでは、ファイルがディスクとメモリに保存される方法と、デフォルトの動作をカスタマイズする方法について説明します。

警告

信頼できないユーザーからアップロードされたコンテンツを受け入れる場合、セキュリティ上のリスクがあります。 緩和策の詳細については、ユーザーがアップロードしたコンテンツに関するセキュリティガイドのトピックを参照してください。


基本的なファイルのアップロード

FileField を含むフォームについて考えてみます。

forms.py

from django import forms

class UploadFileForm(forms.Form):
    title = forms.CharField(max_length=50)
    file = forms.FileField()

このフォームを処理するビューは、 request.FILES でファイルデータを受け取ります。これは、各 FileField (または ImageField 、またはその他ののキーを含むディクショナリです。フォーム内のX181X] FileField サブクラス)。 したがって、上記のフォームのデータにはrequest.FILES['file']としてアクセスできます。

request.FILES には、リクエストメソッドがPOSTであり、少なくとも1つのファイルフィールドが実際に投稿され、リクエストを投稿した<form>に属性enctype="multipart/form-data"。 それ以外の場合、request.FILESは空になります。

ほとんどの場合、アップロードされたファイルをフォームにバインドするで説明されているように、ファイルデータをrequestからフォームに渡します。 これは次のようになります。

views.py

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm

# Imaginary function to handle an uploaded file.
from somewhere import handle_uploaded_file

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_uploaded_file(request.FILES['file'])
            return HttpResponseRedirect('/success/url/')
    else:
        form = UploadFileForm()
    return render(request, 'upload.html', {'form': form})

request.FILES をフォームのコンストラクターに渡す必要があることに注意してください。 これは、ファイルデータがフォームにバインドされる方法です。

アップロードされたファイルを処理する一般的な方法は次のとおりです。

def handle_uploaded_file(f):
    with open('some/file/name.txt', 'wb+') as destination:
        for chunk in f.chunks():
            destination.write(chunk)

read()を使用する代わりにUploadedFile.chunks()をループすることで、大きなファイルがシステムのメモリを圧倒しないようにします。

UploadedFileオブジェクトで使用できる他のメソッドと属性がいくつかあります。 完全なリファレンスについては、 UploadedFile を参照してください。

モデルを使用したアップロードファイルの処理

ModelFileField を使用してファイルを保存する場合、 ModelForm を使用するとこのプロセスがはるかに簡単になります。 ファイルオブジェクトは、form.save()を呼び出すときに、対応する FileFieldupload_to 引数で指定された場所に保存されます。

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import ModelFormWithFileField

def upload_file(request):
    if request.method == 'POST':
        form = ModelFormWithFileField(request.POST, request.FILES)
        if form.is_valid():
            # file is saved
            form.save()
            return HttpResponseRedirect('/success/url/')
    else:
        form = ModelFormWithFileField()
    return render(request, 'upload.html', {'form': form})

オブジェクトを手動で作成している場合は、 request.FILES のファイルオブジェクトをモデルのファイルフィールドに割り当てることができます。

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from .models import ModelWithFileField

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            instance = ModelWithFileField(file_field=request.FILES['file'])
            instance.save()
            return HttpResponseRedirect('/success/url/')
    else:
        form = UploadFileForm()
    return render(request, 'upload.html', {'form': form})

複数のファイルをアップロードする

1つのフォームフィールドを使用して複数のファイルをアップロードする場合は、フィールドのウィジェットのmultiple HTML属性を設定します。

forms.py

from django import forms

class FileFieldForm(forms.Form):
    file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

次に、 FormView サブクラスのpostメソッドをオーバーライドして、複数のファイルのアップロードを処理します。

views.py

from django.views.generic.edit import FormView
from .forms import FileFieldForm

class FileFieldFormView(FormView):
    form_class = FileFieldForm
    template_name = 'upload.html'  # Replace with your template.
    success_url = '...'  # Replace with your URL or reverse().

    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        files = request.FILES.getlist('file_field')
        if form.is_valid():
            for f in files:
                ...  # Do something with each file.
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

ハンドラーのアップロード

ユーザーがファイルをアップロードすると、Djangoはファイルデータをアップロードハンドラーに渡します。これは、アップロード時にファイルデータを処理する小さなクラスです。 アップロードハンドラーは、最初は:setting: `FILE_UPLOAD_HANDLERS` 設定で定義されます。デフォルトは次のとおりです。

["django.core.files.uploadhandler.MemoryFileUploadHandler",
 "django.core.files.uploadhandler.TemporaryFileUploadHandler"]

MemoryFileUploadHandlerTemporaryFileUploadHandler を組み合わせることで、小さなファイルをメモリに、大きなファイルをディスクに読み込むというDjangoのデフォルトのファイルアップロード動作が提供されます。

Djangoがファイルを処理する方法をカスタマイズするカスタムハンドラーを作成できます。 たとえば、カスタムハンドラーを使用して、ユーザーレベルの割り当てを適用したり、データをその場で圧縮したり、プログレスバーをレンダリングしたり、データをローカルに保存せずに別の保存場所に直接送信したりすることもできます。 アップロード動作をカスタマイズまたは完全に置き換える方法の詳細については、カスタムアップロードハンドラーの作成を参照してください。

アップロードされたデータが保存される場所

アップロードしたファイルを保存する前に、データをどこかに保存する必要があります。

デフォルトでは、アップロードされたファイルが2.5メガバイトよりも小さい場合、Djangoはアップロードの内容全体をメモリに保持します。 これは、ファイルの保存にはメモリからの読み取りとディスクへの書き込みのみが含まれるため、非常に高速であることを意味します。

ただし、アップロードされたファイルが大きすぎる場合、Djangoはアップロードされたファイルをシステムの一時ディレクトリに保存されている一時ファイルに書き込みます。 Unixライクなプラットフォームでは、これはDjangoが/tmp/tmpzfp6I6.uploadのようなファイルを生成することを期待できることを意味します。 アップロードが十分に大きい場合は、Djangoがデータをディスクにストリーミングするときにこのファイルのサイズが大きくなるのを見ることができます。

これらの詳細–2.5メガバイト。 /tmp; NS。 –は「合理的なデフォルト」であり、次のセクションで説明するようにカスタマイズできます。


アップロードハンドラの動作の変更

Djangoのファイルアップロード動作を制御するいくつかの設定があります。 詳しくはファイルアップロード設定をご覧ください。


オンザフライでのアップロードハンドラーの変更

特定のビューで異なるアップロード動作が必要になる場合があります。 このような場合、request.upload_handlersを変更することで、リクエストごとにアップロードハンドラーをオーバーライドできます。 デフォルトでは、このリストには:setting: `FILE_UPLOAD_HANDLERS` で指定されたアップロードハンドラーが含まれますが、他のリストと同じようにリストを変更できます。

たとえば、ある種のAJAXウィジェットへのアップロードの進行状況に関するフィードバックを提供するProgressBarUploadHandlerを作成したとします。 このハンドラーをアップロードハンドラーに次のように追加します。

request.upload_handlers.insert(0, ProgressBarUploadHandler(request))

プログレスバーハンドラーは他のハンドラーの前にを実行する必要があるため、この場合は(append()の代わりに)list.insert()を使用することをお勧めします。 アップロードハンドラーは順番に処理されることを忘れないでください。

アップロードハンドラーを完全に置き換える場合は、新しいリストを割り当てることができます。

request.upload_handlers = [ProgressBarUploadHandler(request)]

ノート

request.POSTまたはrequest.FILESにアクセスするの前にアップロードハンドラーを変更することしかできません。アップロード処理がすでに開始された後でアップロードハンドラーを変更することは意味がありません。 request.POSTまたはrequest.FILESから読み取った後にrequest.upload_handlersを変更しようとすると、Djangoはエラーをスローします。

したがって、常にビューのできるだけ早い段階でアップロードハンドラーを変更する必要があります。

また、request.POSTは、デフォルトで有効になっている CsrfViewMiddleware によってアクセスされます。 つまり、アップロードハンドラーを変更できるようにするには、ビューで csrf_exempt()を使用する必要があります。 次に、実際にリクエストを処理する関数で csrf_protect()を使用する必要があります。 これは、CSRFチェックが行われる前にハンドラーがファイルアップロードの受信を開始する可能性があることを意味することに注意してください。 コード例:

from django.views.decorators.csrf import csrf_exempt, csrf_protect

@csrf_exempt
def upload_file_view(request):
    request.upload_handlers.insert(0, ProgressBarUploadHandler(request))
    return _upload_file_view(request)

@csrf_protect
def _upload_file_view(request):
    ... # Process request