Загрузка файлов

Когда Django обрабатывает загрузку файла, данные о нем в конце концов попадают в request.FILES (подробнее об объекте request смотрите в соответствующем разделе). Этот раздел описывает как файлы сохраняются на диск или в памяти и как переопределить это.

Предупреждение

Принимать загруженный контент от непроверенных пользователей – опасно! Подробности смотрите в Контент, загружаемый пользователями.

Основы загрузки файла

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'].

Заметим, что атрибут request.FILES будет содержать данные только при POST запросе и если форма <form> содержит enctype="multipart/form-data". В противном случае request.FILES будет пустым.

Most of the time, you’ll pass the file data from request into the form as described in Привязка загруженных файлов к форме. 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)

Цикл по UploadedFile.chunks(), вместо использования read(), обезопасит вас от нагрузки системы при загрузке большого файла.

Объект UploadedFile содержит и другие методы и атрибуты, смотрите описание UploadedFile.

Обработка загруженных файлов используя модель

Если вы сохраняете файлы для модели Model с FileField, использование ModelForm значительно упростит этот процесс. Файл будет сохранен по указанному в аргументе upload_to поля FileField пути, при вызове form.save():

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

Загрузка нескольких файлов

Если вы хотите загружать несколько файлов в одном поле формы, добавьте HTML атрибут multiple в виджет поля формы:

forms.py
from django import forms

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

Затем переопределите метод post вашего подкласса FormView, чтобы обрабатывать загрузку нескольких файлов:

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

class FileFieldView(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 передает содержимое файла в обработчик загрузки – небольшой класс, который обрабатывает загруженные данные. Обработчики загрузки определенны в настройке FILE_UPLOAD_HANDLERS, по умолчанию:

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

MemoryFileUploadHandler и TemporaryFileUploadHandler определяются обработку файлов по умолчанию в Django, загрузка небольших файлов в память и больших на диск.

Вы можете написать собственный обработчик загрузки файлов. Вы можете использовать его, например, для определения квоты для пользователей на загрузку файлов, сжатие данных «на лету», отображение прогресса загрузки файла, или пересылать файл в хранилище данных без сохранения его локально. Смотрите Writing custom upload handlers, чтобы узнать как настроить или полностью переопределить поведение загрузки.

Где хранятся загруженный данные

Перед тем, как вы сохраните загруженный файл, загруженные данные должны где-то храниться.

По умолчанию, если загруженный файл меньше 2.5 мегабайт, Django поместит содержимое файла в память. Это означает, что при сохранении файла содержимое прочитается с памяти и сохранится на диск, а это быстрая операция.

Однако, если загруженный файл большой, Django запишет его во временный каталог вашей системы. На Unix-системах это означает, что Django создаст, например, такой файл /tmp/tmpzfp6I6.upload. Если загружаемый файл достаточно большой, вы можете отследить, как увеличивается размер файла, в процессе загрузки данных.

These specifics – 2.5 megabytes; /tmp; etc. – are «reasonable defaults» which can be customized as described in the next section.

Изменение процесса загрузки

Процесс загрузки файлов использует несколько настроек. Подробности смотрите в разделе настроек.

Изменение обработчиков загрузки файла «на лету»

Иногда различные представления требуют различной обработки загруженных файлов. В таких случаях вы можете переопределить обработчики загрузки, изменив request.upload_handlers. По умолчанию этот атрибут содержит обработчики из настройки FILE_UPLOAD_HANDLERS, но вы можете изменить его.

Например, вы создали ProgressBarUploadHandler, который уведомляет страницу через AJAX-запросы о прогрессе загрузки файла . Вы можете использовать его таким образом:

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

Использование list.insert() в этом случае (вместо append()) буде уместней, так как обработчик, уведомляющий о прогрессе загрузки, должен использоваться перед другими обработчиками. Запомните, обработчики загрузки используются по-порядку.

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.upload_handlers после использования request.POST или request.FILES, 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