Отправка файлов

Когда 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 или любого другого подкласса FileField ) формы. Таким образом, данные из приведенной выше формы будут доступны в формате request.FILES['file'] .

Обратите внимание, что он request.FILES содержит данные только в том случае, если используется метод запроса, POST а запрашивающая форма <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)

Выполняя цикл 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})

Если вы создаете объект вручную, вы можете назначить файл из объекта 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})

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

Если вы хотите разрешить загрузку нескольких файлов с использованием одного поля формы, установите атрибут 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 по умолчанию, помещая небольшие файлы в память, а большие - на диск.

Вы можете написать собственные обработчики, которые изменят способ управления файлами. Например, вы можете использовать настраиваемые обработчики, чтобы ограничить объем данных для каждого пользователя, сжимать данные на лету, отображать индикаторы выполнения или даже отправлять данные непосредственно в другое место хранения, не сохраняя их локально. См. Раздел Написание пользовательских обработчиков загрузки для получения дополнительных сведений о том, как настроить или полностью переопределить поведение загрузки.

Место хранения данных

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

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

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

Эти конкретные параметры, 2,5 МБ /tmp и т. Д. являются просто «разумными» значениями по умолчанию, которые можно настроить, как описано в следующем разделе.

Модификация управления загрузкой

Есть некоторые настройки для управления поведением загрузки файлов Django. См. Подробности в разделе « Настройки загрузки файлов» .

Редактирование обработчиков загрузки на лету

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

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

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

В этом случае это list.insert() может быть более подходящим, чем append() потому, что менеджер индикатора выполнения должен запускаться раньше любого другого менеджера. Помните, что обработчики загрузки вызываются по порядку.

Если вы хотите полностью заменить менеджеры загрузки, просто назначьте новый список:

request.upload_handlers = [ProgressBarUploadHandler(request)]

Заметка

Изменить обработчики загрузки можно только перед доступом request.POST или request.FILES , поскольку не имеет смысла изменять обработчики загрузки после того, как обработка загрузки уже началась. Если вы все равно это сделаете, Django выдаст ошибку.

Однако изменение обработчиков загрузки всегда должно происходить в представлениях как можно раньше.

Кроме того, CsrfViewMiddleware по умолчанию доступ к промежуточному программному обеспечению включен request.POST . Это означает, что необходимо украсить 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

Copyright ©2020 All rights reserved