Загрузка файлов
При обработке Django загрузки файла, данные файла оказываются помещёнными в request.FILES (подробнее об объекте request см. документацию по объектам запроса и ответа). В данном документе описывается, как файлы хранятся на диске и в памяти, а также как настроить поведение по умолчанию.
Предупреждение
При приёме загружаемого контента от ненадежных пользователей существуют риски безопасности! Подробности по смягчению последствий см. в разделе руководства по безопасности о безопасности контента, загружаемого пользователем.
Базовая загрузка файлов
Рассмотрим простую форму, содержащую FileField:
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 в форму, как описано в Связывание загруженных файлов с формой. Это будет выглядеть примерно так:
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})
Загрузка нескольких файлов
Если вы хотите загрузить несколько файлов, используя одно поле формы, установите атрибут multiple виджета поля:
from django import forms
class FileFieldForm(forms.Form):
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
Затем переопределите метод post вашего FormView подкласса для обработки многократной загрузки файлов:
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 по умолчанию — чтение небольших файлов в память, а больших — на диск.
Вы можете написать пользовательские обработчики, которые настраивают то, как Django обрабатывает файлы. Например, вы можете использовать пользовательские обработчики для принудительного применения квот на уровне пользователя, сжатия данных на лету, отображения полосы прогресса и даже отправки данных в другое хранилище напрямую, без локального сохранения. Подробности о том, как вы можете настроить или полностью заменить поведение загрузки, см. в разделе Создание пользовательских обработчиков загрузки.
Где хранятся загруженные данные
Перед сохранением загруженных файлов данные должны быть сохранены где-то.
По умолчанию, если загруженный файл меньше 2,5 мегабайт, Django будет хранить всё содержимое загрузки в оперативной памяти. Это означает, что сохранение файла включает только чтение из памяти и запись на диск, и поэтому очень быстро.
Однако, если загруженный файл слишком большой, Django запишет загруженный файл во временный файл, хранящийся в временном каталоге вашей системы. В операционной системе типа Unix это означает, что Django может сгенерировать файл с именем, подобным /tmp/tmpzfp6I6.upload. Если загрузка достаточно велика, вы можете наблюдать, как размер этого файла увеличивается по мере потоковой передачи данных Django на диск.
Эти специфики — 2,5 мегабайта; /tmp; и т. д. — просто «разумные значения по умолчанию», которые можно настроить, как описано в следующем разделе.
Изменение поведения обработчиков загрузки
Существует несколько настроек, которые контролируют поведение загрузки файлов в Django. Подробности см. в Настройки загрузки файлов.
Изменение обработчиков загрузки в процессе выполнения
Иногда для определённых представлений требуется другое поведение загрузки. В этих случаях вы можете переопределить обработчики загрузки на основе каждого запроса, изменив request.upload_handlers. По умолчанию этот список будет содержать обработчики загрузки, указанные в FILE_UPLOAD_HANDLERS, но вы можете изменить список, как любой другой список.
Например, предположим, что вы написали обработчик, который предоставляет обратную связь о прогрессе загрузки в какой-то виджет AJAX. Вы добавите этот обработчик в свои обработчики загрузки так:
request.upload_handlers.insert(0, ProgressBarUploadHandler(request))
В этом случае, вы, вероятно, захотите использовать list.insert() (вместо append()), поскольку обработчик прогресса загрузки должен выполняться перед другими обработчиками. Помните, обработчики загрузки обрабатываются в порядке.
Если вы хотите полностью заменить обработчики загрузки, вы можете просто присвоить новый список:
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
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/