# Django 4.1.8.dev20230308103347 ドキュメント

# ファイルのアップロード

Django がファイルアップロードを扱うとき、ファイルデータは `request.FILES` に格納されます (`request` についての詳細は request and response objects をご覧ください)。ここでは、ファイルがどのようにディスクとメモリに保管され、またどうやってデフォルトの動作を変更するかを説明します。

警告

信頼できないユーザーからコンテンツアップロードを許可する場合、セキュリティリスクが存在します！緩和策の詳細は、ユーザーがアップロードしたコンテンツ のセキュリティガイドをご覧ください。

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

Consider a form containing a `FileField`:

`forms.py`

    from django import forms

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

このフォームをハンドリングするビューは、ファイルのデータを `request.FILES` というディクショナリの中に受け取ります。このディクショナリには、キーと、それぞれのキーに対応するフォームの `FileField` (または `ImageField` または他の `FileField` のサブクラス) が格納されています。そのため、上のフォームから送信されたデータには、`request.FILES['file']` でアクセスすることができます。

Note that `request.FILES` will only contain data if the request method was `POST`, at least one file field was actually posted, and the `<form>` that posted the request has the attribute `enctype="multipart/form-data"`. Otherwise, `request.FILES` will be empty.

Most of the time, you'll pass the file data from `request` into the form as described in Binding uploaded files to a form. This would look something like:

`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` を読んでください。

### モデルを使用したアップロードファイルのハンドリング

`FileField` を持つ `Model` 上のファイルを保存するときは、`ModelForm` を使えば、このプロセスはとても簡単になります。この場合、ファイルオブジェクトは、`form.save()` を呼び出すだけで、対応する `FileField` の `upload_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})

If you are constructing an object manually, you can assign the file object from `request.FILES` to the file field in the model:

    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})

If you are constructing an object manually outside of a request, you can assign a `File` like object to the `FileField`:

    from django.core.management.base import BaseCommand
    from django.core.files.base import ContentFile

    class MyCommand(BaseCommand):
        def handle(self, *args, **options):
            content_file = ContentFile(b'Hello world!', name='hello-world.txt')
            instance = ModelWithFileField(file_field=content_file)
            instance.save()

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

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 はそのファイルのデータを アップロードハンドラ (upload handler) という、ファイルがアップロードされた時にデータをハンドリングするための小さなクラスへ渡します。アップロードハンドラは、初めに設定の `FILE_UPLOAD_HANDLERS` で定義されています。デフォルトでは次のようになっています。

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

`MemoryFileUploadHandler` と `TemporaryFileUploadHandler` はともに、Django でファイルがアップロードされた時のデフォルトの動作――小さなファイルはメモリ上に保存し、大きなファイルはディスクに保存する――を提供しています。

カスタマイズハンドラを書けば、Django がファイルをハンドリングする方法をカスタマイズすることができます。たとえば、カスタムハンドラを使うことで、ユーザレベルでのクオータを設定したり、データをその場で圧縮したり、プログレスバーを表示したり、あるいは、送られたデータをローカルに保存せずに、別のストレージに転送することさえ可能です。ハンドラをカスタマイズしたり、アップロード時の動作を完全に置き換えたりする方法については、詳しくは アップロードハンドラをカスタマイズする を読んでください。

### アップロードされたデータの保存場所

アップロードされたファイルを保存する時点で、そのデータはコンピュータ上のどこかに保存されているはずです。

デフォルトでは、アップロードファイルが 2.5 MB 未満ならば、Django はデータ全体をメモリ上に保持します。つまり、この場合にファイルを保存するというのは、メモリ上からデータを読み込んでディスクにファイルを書き込むだけなので、処理は短時間しかかかりません。

しかし、アップロードファイルのサイズが大きい場合、Django はアップロードファイルをシステムの一時ディレクトリ内に、一時ファイルとして保存します。Unix-like なプラットフォームなら、Django は `/tmp/tmpzfp6I6.upload` のようなファイルを作成すると考えて良いです。アップロードされたファイルが十分大きければ、Django がデータストリームをディスクに書き込むにつれ、このファイルのサイズが大きくなってゆくのを観察することができるでしょう。

These specifics -- 2.5 megabytes; `/tmp`; etc. -- are "reasonable defaults" which can be customized as described in the next section.

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

Django のファイルアップロードの動作を制御するための設定がいくつかあります。詳しくは、 File Upload Settings を参照してください。

### その場でアップロードハンドラを修正する

時として特定のビューが異なるアップロード動作を必要とすることがあります。このような場合には、`request.upload_handlers` を修正することで、1リクエストごとに、アップロードハンドラをオーバーライドすることが可能です。デフォルトでは、このリストには `FILE_UPLOAD_HANDLERS` の設定で指定したアップロードハンドラが入っていますが、このリストは自由に修正することができます。

たとえば、アップロードの進行状況を計算して、AJAX のウィジェットなどにフィードバックを返す `ProgressBarUploadHandler` というハンドラを作ったとしましょう。このハンドラを、次のようにアップロードハンドラのリストに追加します。

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

この場合には、`list.append()` メソッドの代わりに `list.insert()` を使ったほうが良いでしょう。なぜなら、プログレスバーハンドラーは、他のハンドラの 前に 実行する必要があるでしょうから。アップロードハンドラは、リストの前から順に処理されることに注意してください。

If you want to replace the upload handlers completely, you can assign a new list:

    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

If you are using a class-based view, you will need to use `csrf_exempt()` on its `dispatch()` method and `csrf_protect()` on the method that actually processes the request. Example code:

    from django.utils.decorators import method_decorator
    from django.views import View
    from django.views.decorators.csrf import csrf_exempt, csrf_protect

    @method_decorator(csrf_exempt, name='dispatch')
    class UploadFileView(View):

        def setup(self, request, *args, **kwargs):
            request.upload_handlers.insert(0, ProgressBarUploadHandler(request))
            super().setup(request, *args, **kwargs)

        @method_decorator(csrf_protect)
        def post(self, request, *args, **kwargs):
            ... # Process request