Загрузка файлов
Когда Django обрабатывает загрузку файла, данные файла размещаются в request.FILES (подробнее об объекте request см. документацию по объектам запроса и ответа). В данном документе объясняется, как файлы хранятся на диске и в памяти, а также как настроить поведение по умолчанию.
Предупреждение
Существуют риски безопасности, если вы принимаете загружаемое содержимое от ненадежных пользователей! См. раздел руководства по безопасности о безопасности пользовательского содержимого для получения информации о смягчении последствий.
Базовая загрузка файлов
Рассмотрим простую форму, содержащую FileField:
# In 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 в форму, как описано в Связывание загруженных файлов с формой. Это будет выглядеть примерно так:
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
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_to_response('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})
Обработчики загрузки
Когда пользователь загружает файл, 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, но вы можете изменить список, как и любой другой список.
Например, предположим, что вы написали ProgressBarUploadHandler для предоставления обратной связи о прогрессе загрузки в каком-либо виджете 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/1.8/topics/http/file-uploads/