Spec-Zone.ru › Django 1.10

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

При обработке 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 HTML виджета поля:

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

Например, предположим, что вы написали 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.10/topics/http/file-uploads/

Spec-Zone.ru

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