Spec-Zone.ru › Django 3.2

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

Когда 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, был опубликован хотя бы один поле файла, и пользователь, который опубликовал запрос, имеет атрибут 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})

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

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

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.2/topics/http/file-uploads/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API