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

Когда 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с помощью a FileField, использование a 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 атрибут HTML виджета поля:

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.FILESDjango выдаст ошибку.

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

Кроме того, 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

Copyright ©2021 All rights reserved