Правильный аксессор для загруженных файлов Django - PullRequest
2 голосов
/ 22 марта 2011

Принимая форму Джанго, подобную следующей ...

class MyForm(forms.Form):
    attachment = forms.FileField()

Я видел много учебных пособий, в которых доступ к загруженным файлам Django осуществляется с помощью request.FILES['attachment'], однако у меня сложилось впечатление, что при любой возможности вы должны получить доступ к POST редактированным данным через form.cleaned_data['attachment'].

Есть ли причина, по которой можно использовать request.FILES[]? Должны ли эти объекты содержать одинаковые данные?

1 Ответ

7 голосов
/ 22 марта 2011

Когда вы создаете форму в HTML, она имеет определенную кодировку (или метод отправки данных на сервер).По умолчанию используется кодировка application/x-www-form-urlencoded, которая по существу отправляет сведения о форме в одной строке.Однако, если вы хотите загрузить файлы на сервер, вам нужно установить кодировку на multipart/form-data (это строка enctype="...", которую вы заметите во всех руководствах по этой теме).Это отправляет данные в несколько частей, по одной на поле формы.Для примера того, как выглядят эти две кодировки, см. Здесь .

Когда Django встречает кодировку multipart/form-data, он разбивает полученные данные на два словаря: словарь request.FILES содержит любойзагруженные файлы, в то время как request.POST содержит любые другие поля формы.Если вам интересно, обработка выполняется классом MultiPartParser в файле django/http/__init__.py.

Чтобы проиллюстрировать, как эти данные возвращаются в ваш код, давайте создадим простое приложение.Во-первых, давайте создадим простую форму, состоящую из символьного поля и поля файла:

from django import forms

class TestForm(forms.Form):
    name = forms.CharField()
    file = forms.FileField()

Далее, мы создадим простое представление для создания формы, привязки к ней любых отправленных данных и их рендеринга.через шаблон:

from django.shortcuts import render_to_response
from django.template import RequestContext

from forms import TestForm

def show_form(request):
    if request.method == 'POST':
        form = TestForm(request.POST, request.FILES)
    else:
        form = TestForm()

    context = {
        'form': form
    }
    return render_to_response('show_form.html', context, RequestContext(request))

И, наконец, мы будем использовать шаблон для отображения формы и некоторой информации как о запросе, так и о форме:

<html>
    <head>
        <title>Django forms - file test</title>
    </head>

    <body>
        <form method="post" enctype="multipart/form-data">
            {% csrf_token %}
            {{ form.as_p }}
            <input type="submit" />
        </form>

        <h2>Request details</h2>

        <p>
        Request method: {{ request.method }}
        <br />
        POST data: {{ request.POST|default:"No data" }}
        <br />
        FILES data: {{ request.FILES|default:"No data" }}
        </p>

        <h2>Form details</h2>

        <p>
        Cleaned data: {{ form.cleaned_data|default:"No data" }}
        </p>

    </body>
</html>

Обратите внимание, что вы 'Вам нужно будет включить контекстный процессор django.core.context_processors.request в ваших настройках, чтобы увидеть подробности о запросе.

Если мы затем запустим сервер и направим наш браузер на просмотр, мы увидимто, что мы ожидали увидеть - пустая форма, режим запроса был GET, и не было POST, FILES или данных формы.

Далее, введите имя в поле символа, но не выбирайтефайл для загрузки.После отправки мы получаем ожидаемую ошибку об обязательном заполнении поля файла.Для нас более интересна информация о запросе:


Детали запроса

Метод запроса: POST
Данные POST:
Данные ФАЙЛОВ: Нет данных

Детали формы

Очищенные данные: Нет данных


Поскольку информация о файлах не была отправлена ​​браузером, Django добавилвсе детали формы в словаре POST и оставил словарь FILES пустым.Поскольку форма недействительна, с ней не связано никаких данных.

Теперь давайте попробуем использовать ее без имени, но с файлом для загрузки:


Запросить информацию

Метод запроса: POST
Данные POST:
ФАЙЛЫ:]}>

Сведения о форме

Очищенные данные: нет данных


Теперь отправленные данные разделены между словарями POST и FILES.К файлу можно получить доступ через request.FILES['file'], но не через данные, очищенные от форм, так как форма была признана недействительной из-за отсутствия имени.Поскольку загруженный мною файл был небольшим, он хранится в памяти;файлы выше определенного размера (по умолчанию 2,5 МБ) будут храниться во временном каталоге, но ваш код может обрабатывать их одинаково.

Наконец, давайте попробуем сделать это со значениями для обоих полей:


Детали запроса

Способ запроса: POSTДанные POST:ФАЙЛЫ данные:]}>

Сведения о форме

Чистые данные: {'name': u'Blair ',' file ':}


Поскольку данные действительны и привязаны к форме, к файлу также можно получить доступ через cleaned_data формы.

Потенциальная выгода от доступа к нему через request.FILES: если форма недействительна, вы все равно можете сохранить файл где-нибудь, прежде чем попросить пользователя исправить данные.Это предотвращает необходимость повторной загрузки файла (что может быть довольно затратным с точки зрения времени и пропускной способности, если вы работаете с большими файлами).Если вы хотите работать только с небольшими файлами, это не будет иметь большого значения, но, вероятно, лучше использовать request.FILES.Так же поступает документация по загрузке файлов Django .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...