Загрузка файлов
При обработке загрузки файлов Django помещает данные файла в request.FILES (подробнее об объекте request см. документацию по объектам запроса и ответа). Этот документ объясняет, как файлы хранятся на диске и в памяти, а также как настроить поведение по умолчанию.
Предупреждение
Существуют риски безопасности, если вы принимаете загружаемое содержимое от недоверенных пользователей! См. тему руководства по безопасности о безопасности содержимого, загружаемого пользователем для получения подробной информации о методах защиты.
Базовая загрузка файлов
Рассмотрим форму, содержащую FileField:
forms.pyfrom 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.pyfrom 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})
Если вы создаете объект вручную вне запроса, вы можете назначить объект-аналог File полю 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()
Загрузка нескольких файлов
Если вы хотите загрузить несколько файлов с помощью одного поля формы, установите атрибут multiple HTML виджета поля:
forms.pyfrom django import forms
class FileFieldForm(forms.Form):
file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
Затем переопределите метод post вашего подкласса FormView, чтобы обработать многократную загрузку файлов:
views.pyfrom 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 передает данные файла обработчику загрузки — небольшому классу, который обрабатывает данные файла во время загрузки. Обработчики загрузки первоначально определяются в настройке 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
Если вы используете представление на основе класса, вам необходимо использовать csrf_exempt() в его методе dispatch() и csrf_protect() в методе, который фактически обрабатывает запрос. Пример кода:
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
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.1/topics/http/file-uploads/