HTML-формы
HTML форма – это набор элементов внутри <form> … </ form>, которые позволяют посетителю выполнять такие действия, как ввод текста, выбор параметров или управление объектами и т. д., а затем отправлять эту информацию обратно на сервер.
Некоторые из этих элементов интерфейса формы – поля ввода текста или флажки – встроены в сам HTML. Другие намного сложнее, например календари, обычно использует JavaScript и CSS, а также элементы HTML <input> для достижения этих эффектов.
Помимо элементов <input>, форма должна содержать две вещи:
- URL, на который должны быть возвращены данные, соответствующие вводу пользователя
- метод HTTP которым , данные должны быть возвращены
Кроме того форма должна быть связана с элементом вызывающим отправку формы на сервер, часто это <input type=”submit”>
Формы передаются методами GET (используется для открытия пустых форм или начальных форм) или POST (для передачи данных на сервер). Это связано с тем, что метод GET, объединяет отправленные данные в строку и использует ее для составления URL. Кроме того метод POST требует наличие специальных полей CSRF защиты.
Метод GET очень полезен для форм поиска, так как может быть просто сохранен и использован заново (например в закладках браузера)
Django обрабатывает следующие функции, связанные с формами:
- подготовка и реструктуризация данных, чтобы они были готовы к визуализации
- создание HTML-форм для данных
- прием и обработка отправленных форм и данных от клиента
Можно написать код, который делает все это вручную, но Django может позаботиться обо всем за вас.
Формы в DJANGO
В основе этой системы компонентов лежит класс Form. Во многом так же, как модель Django описывает логическую структуру объекта, его поведение и способ представления его частей, класс Form описывает форму и определяет, как он работает и выглядит.
Аналогично тому, как поля класса модели отображаются на поля базы данных, поля класса формы отображаются на элементы <input> HTML-формы. (ModelForm отображает поля класса модели в HTML-элементы <input> формы через класс Form; на этом механизме основан администратор Django.)
Поля формы сами по себе являются классами; они управляют данными формы и выполняют проверку при отправке формы. DateField и FileField обрабатывают очень разные виды данных и должны делать с ними разные вещи.
Поле формы представляется пользователю в браузере как HTML-виджет – часть механизма пользовательского интерфейса. Каждый тип поля имеет соответствующий класс Widget, но они могут быть переопределены при необходимости.
Создание, обработка и рендеринг форм
При рендеринге объекта в Django мы обычно:
- получить данные для представления (например, получить их из базы данных)
- передать данные в контекст шаблона
- перевести данные в форму HTML-разметки, используя переменные шаблона
Рендеринг формы в шаблоне включает в себя почти ту же работу, что и рендеринг любого другого типа объекта, но есть некоторые ключевые отличия.
В случае экземпляра модели, который не содержал данных, бесполезно что-либо делать с ним в шаблоне. С другой стороны, имеет смысл представить незаполненную форму – это то, что мы делаем, когда хотим, чтобы пользователь заполнил ее.
Поэтому, когда мы обрабатываем экземпляр модели в представлении, мы обычно получаем его из базы данных. Когда мы имеем дело с формой, мы обычно создаем ее экземпляр в представлении.
Когда мы создаем экземпляр формы, мы можем оставить ее пустой или предварительно заполнить, например, с помощью:
- данные из сохраненного экземпляра модели (как в случае административных форм для редактирования)
- данные, которые мы собрали из других источников
- данные, полученные из предыдущей отправки формы HTML
Последний из этих случаев является наиболее интересным, поскольку он позволяет пользователям не только читать веб-сайт, но и отправлять на него информацию.
Создание форм в Django
Отправной точкой создания формы в Django является написание класса наследника от Form:
1 2 3 4 |
<span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span> <span class="k">class</span> <span class="nc">NameForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span> <span class="n">your_name</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">label</span><span class="o">=</span><span class="s1">'Your name'</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span> |
В примере мы определяем наследника класса Form с одним полем (your_name). Мы применили к полю удобную для человека метку, которая будет отображаться в <label>, когда она будет отображаться (хотя в этом случае указанная нами метка на самом деле будет такой же, что и в случаи автоматической генерации, если мы ее опустим параметр label)
Максимально допустимая длина поля определяется max_length. При ее определении будет указан параметр maxlength = “100” в HTML <input> (поэтому браузер должен в первую очередь запрещать пользователю вводить больше, чем это количество символов). Это также означает, что когда Django получит форму обратно из браузера, она проверит длину данных.
Экземпляр формы имеет метод is_valid (), который выполняет процедуры проверки для всех своих полей. Когда этот метод вызывается, если все поля содержат корректные данные, то он:
- верните True
- поместите данные формы в ее атрибут cleaned_data.
Вся форма при первом отображении будет выглядеть так:
1 2 |
<span class="p"><</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">"your_name"</span><span class="p">></span>Your name: <span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">input</span> <span class="na">id</span><span class="o">=</span><span class="s">"your_name"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text"</span> <span class="na">name</span><span class="o">=</span><span class="s">"your_name"</span> <span class="na">maxlength</span><span class="o">=</span><span class="s">"100"</span> <span class="na">required</span><span class="p">></span> |
Обратите внимание, что он не включает теги <form> или кнопку отправки. Мы должны предоставить их сами в шаблоне.
Представление (View)
Данные формы, отправленные обратно на веб-сайт Django, обрабатываются представлением, обычно тем же, в котором опубликована форма. Это позволяет нам повторно использовать одну и ту же логику.
Чтобы обработать форму, нам нужно создать ее экземпляр в представлении для URL, где мы хотим, чтобы она была опубликована:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<span class="kn">from</span> <span class="nn">django.http</span> <span class="kn">import</span> <span class="n">HttpResponseRedirect</span> <span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span> <span class="kn">from</span> <span class="nn">.forms</span> <span class="kn">import</span> <span class="n">NameForm</span> <span class="k">def</span> <span class="nf">get_name</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="c1"># if this is a POST request we need to process the form data</span> <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s1">'POST'</span><span class="p">:</span> <span class="c1"># create a form instance and populate it with data from the request:</span> <span class="n">form</span> <span class="o">=</span> <span class="n">NameForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">POST</span><span class="p">)</span> <span class="c1"># check whether it's valid:</span> <span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span> <span class="c1"># process the data in form.cleaned_data as required</span> <span class="c1"># ...</span> <span class="c1"># redirect to a new URL:</span> <span class="k">return</span> <span class="n">HttpResponseRedirect</span><span class="p">(</span><span class="s1">'/thanks/'</span><span class="p">)</span> <span class="c1"># if a GET (or any other method) we'll create a blank form</span> <span class="k">else</span><span class="p">:</span> <span class="n">form</span> <span class="o">=</span> <span class="n">NameForm</span><span class="p">()</span> <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">'name.html'</span><span class="p">,</span> <span class="p">{</span><span class="s1">'form'</span><span class="p">:</span> <span class="n">form</span><span class="p">})</span> |
Если мы придем к этому представлению с помощью запроса GET, он создаст пустой экземпляр формы и поместит его в контекст шаблона для визуализации. Это то, что мы можем ожидать при первом посещении URL.
Если форма отправляется с использованием запроса POST, представление снова создаст экземпляр формы и заполнит его данными из запроса: form = NameForm (request.POST) Это называется «привязка данных к форме» (теперь это связанная форма).
Мы вызываем метод is_valid () формы; если это не правда, мы возвращаемся к шаблону с формой. На этот раз форма больше не является пустой (несвязанной), поэтому форма HTML будет заполнена ранее отправленными данными, где ее можно будет редактировать и исправлять по мере необходимости.
Если is_valid () имеет значение True, мы теперь сможем найти все проверенные данные формы в его атрибуте cleaned_data. Мы можем использовать эти данные для обновления базы данных или другой обработки перед отправкой HTTP-перенаправления в браузер, сообщая ему, куда идти дальше.
Шаблон
Шаблон будет иметь довольно простой вид:
1 2 3 4 5 |
<span class="p"><</span><span class="nt">form</span> <span class="na">action</span><span class="o">=</span><span class="s">"/your-name/"</span> <span class="na">method</span><span class="o">=</span><span class="s">"post"</span><span class="p">></span> <span class="cp">{%</span> <span class="k">csrf_token</span> <span class="cp">%}</span> <span class="cp">{{</span> <span class="nv">form</span> <span class="cp">}}</span> <span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">"submit"</span> <span class="na">value</span><span class="o">=</span><span class="s">"Submit"</span><span class="p">></span> <span class="p"></</span><span class="nt">form</span><span class="p">></span> |
Все поля формы и их атрибуты будут распакованы в разметку HTML из {{form}} с помощью языка шаблонов Django.
Django поставляется с простой в использовании защитой от подделок межсайтовых запросов. При отправке формы через POST с включенной защитой CSRF необходимо использовать тег шаблона csrf_token, как в предыдущем примере.
Если ваша форма содержит URLField, EmailField или любой другой тип целочисленного поля, Django будет использовать URL-адреса, адреса электронной почты и числовые типы ввода HTML5. По умолчанию браузеры могут применять свою собственную проверку к этим полям, которая может быть более строгой, чем проверка Django. Если вы хотите отключить это поведение, установите атрибут novalidate в теге формы или укажите другой виджет в поле, например TextInput.
Теперь у нас есть рабочая веб-форма, описанная формой Django, обработанная представлением и представленная в виде HTML <form>.
Это все, что вам нужно для начала, но фреймворк форм дает вам гораздо больше.
Особенности классов Form и ModelForm
Все классы форм создаются как подклассы django.forms.Form или django.forms.ModelForm. Вы можете думать о ModelForm как о подклассе Form. Form и ModelForm на самом деле наследуют общие функциональные возможности от (частного) класса BaseForm, но эта деталь реализации редко важна.
Фактически, если ваша форма будет использоваться для непосредственного добавления или редактирования модели Django, ModelForm может сэкономить вам много времени, усилий и кода, поскольку она создаст форму вместе с соответствующими полями и их атрибутами. из модельного класса.
Связанные и несвязанные экземпляры формы
Различие между связанными и несвязанными формами важно:
- Несвязанная форма не имеет данных, связанных с ней. Когда она отображается для пользователя, то будет пустой или содержать значения по умолчанию.
- Связанная форма представляет данные и, следовательно, может быть использована для определения правильности этих данных. Если отображается недопустимая связанная форма, она может включать встроенные сообщения об ошибках, сообщающие пользователю, какие данные необходимо исправить.
Атрибут is_bound формы сообщит вам, привязаны ли к форме данные или нет.
Пример реализации формы «свяжитесь со мной» на персональном веб-сайте:
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="k">if</span> <span class="n">form</span><span class="o">.</span><span class="n">is_valid</span><span class="p">():</span> <span class="n">subject</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">'subject'</span><span class="p">]</span> <span class="n">message</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">'message'</span><span class="p">]</span> <span class="n">sender</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">'sender'</span><span class="p">]</span> <span class="n">cc_myself</span> <span class="o">=</span> <span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s1">'cc_myself'</span><span class="p">]</span> <span class="n">recipients</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'info@example.com'</span><span class="p">]</span> <span class="k">if</span> <span class="n">cc_myself</span><span class="p">:</span> <span class="n">recipients</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">sender</span><span class="p">)</span> <span class="n">send_mail</span><span class="p">(</span><span class="n">subject</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">sender</span><span class="p">,</span> <span class="n">recipients</span><span class="p">)</span> <span class="k">return</span> <span class="n">HttpResponseRedirect</span><span class="p">(</span><span class="s1">'/thanks/'</span><span class="p">)</span> |
В нашей предыдущей форме использовалось одно поле, your_name, CharField. В этом случае наша форма имеет четыре поля: subject (тема), message (сообщение), sender (отправитель ) и cc_myself. CharField, EmailField и BooleanField – это только три из доступных типов полей, более полный список можно обнаружить в документации.
Некоторые типы полей нуждаются в дополнительной обработке. Например, файлы, загруженные с помощью формы, должны обрабатываться по-разному (их можно получить из request.FILES, а не request.POST).
Работа с шаблонами
Все, что вам нужно сделать, чтобы поместить вашу форму в шаблон, это поместить экземпляр формы в контекст шаблона. Поэтому, если ваша форма называется формой в контексте, {{form}} будет соответствующим образом отображать ее элементы <label> и <input>.
Существуют и другие параметры вывода для пар <label> / <input>:
- {{form.as_table}} отобразит их как ячейки таблицы, обернутые в теги <tr>
- {{form.as_p}} отобразит их в тегах <p>
- {{form.as_ul}} отобразит их в тегах <li>
Обратите внимание, что вам придется предоставить окружающие элементы <table> или <ul> самостоятельно.
Пример вывода {{form.as_p}} для экземпляра ContactForm (см. выше):
1 2 3 4 5 6 7 |
<span class="p"><</span><span class="nt">input</span> <span class="na">id</span><span class="o">=</span><span class="s">"id_subject"</span> <span class="na">type</span><span class="o">=</span><span class="s">"text"</span> <span class="na">name</span><span class="o">=</span><span class="s">"subject"</span> <span class="na">maxlength</span><span class="o">=</span><span class="s">"100"</span> <span class="na">required</span><span class="p">></</span><span class="nt">p</span><span class="p">></span> <span class="p"><</span><span class="nt">p</span><span class="p">><</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">"id_message"</span><span class="p">></span>Message:<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">textarea</span> <span class="na">name</span><span class="o">=</span><span class="s">"message"</span> <span class="na">id</span><span class="o">=</span><span class="s">"id_message"</span> <span class="na">required</span><span class="p">></</span><span class="nt">textarea</span><span class="p">></</span><span class="nt">p</span><span class="p">></span> <span class="p"><</span><span class="nt">p</span><span class="p">><</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">"id_sender"</span><span class="p">></span>Sender:<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">"email"</span> <span class="na">name</span><span class="o">=</span><span class="s">"sender"</span> <span class="na">id</span><span class="o">=</span><span class="s">"id_sender"</span> <span class="na">required</span><span class="p">></</span><span class="nt">p</span><span class="p">></span> <span class="p"><</span><span class="nt">p</span><span class="p">><</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">"id_cc_myself"</span><span class="p">></span>Cc myself:<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="p"><</span><span class="nt">input</span> <span class="na">type</span><span class="o">=</span><span class="s">"checkbox"</span> <span class="na">name</span><span class="o">=</span><span class="s">"cc_myself"</span> <span class="na">id</span><span class="o">=</span><span class="s">"id_cc_myself"</span><span class="p">></</span><span class="nt">p</span><span class="p">></span> |
Обратите внимание, что каждое поле формы имеет атрибут ID, установленный в id_ <field-name>, на который ссылается сопровождающий тег label. Это важно для обеспечения доступности форм для вспомогательных технологий, таких как программное обеспечение для чтения с экрана (эти параметры можно настроить).
Рендеринг полей вручную
Нам не нужно позволять Django распаковывать поля формы; мы можем сделать это вручную, если захотим (например, что позволит нам изменить порядок полей). Каждое поле доступно как атрибут формы, используя {{form.name_of_field}}, и в шаблоне Django будет отображаться соответствующим образом. Например:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<span class="cp">{</span> <span class="nv">form.non_field_errors</span> <span class="cp">}}</span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"fieldWrapper"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.subject.errors</span> <span class="cp">}}</span> <span class="p"><</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">form.subject.id_for_label</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>Email subject:<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.subject</span> <span class="cp">}}</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"fieldWrapper"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.message.errors</span> <span class="cp">}}</span> <span class="p"><</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">form.message.id_for_label</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>Your message:<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.message</span> <span class="cp">}}</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"fieldWrapper"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.sender.errors</span> <span class="cp">}}</span> <span class="p"><</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">form.sender.id_for_label</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>Your email address:<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.sender</span> <span class="cp">}}</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"fieldWrapper"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.cc_myself.errors</span> <span class="cp">}}</span> <span class="p"><</span><span class="nt">label</span> <span class="na">for</span><span class="o">=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">form.cc_myself.id_for_label</span> <span class="cp">}}</span><span class="s">"</span><span class="p">></span>CC yourself?<span class="p"></</span><span class="nt">label</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.cc_myself</span> <span class="cp">}}</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> |
Полные элементы <label> также можно сгенерировать с помощью label_tag (). Например:
1 2 3 4 5 |
<span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"fieldWrapper"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">form.subject.errors</span> <span class="cp">}}</span> <span class="cp">{{</span> <span class="nv">form.subject.label_tag</span> <span class="cp">}}</span> <span class="cp">{{</span> <span class="nv">form.subject</span> <span class="cp">}}</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> |
Отображение сообщений об ошибках формы
Конечно, цена этой гибкости больше работы. До сих пор нам не приходилось беспокоиться о том, как отображать ошибки формы, но в полном примере мы должны предусмотреть вывод сообщений об ошибках. В примере Выше предусмотрен вывод сообщений о любых ошибках для каждого поля и об ошибках в форме в целом. Обратите внимание на {{form.non_field_errors}} в верхней части формы и шаблон поиска ошибок в каждом поле.
Использование {{form.name_of_field.errors}} отображает список ошибок формы, представленных как неупорядоченный список. Это может выглядеть так:
1 2 3 |
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"errorlist"</span><span class="p">></span> <span class="p"><</span><span class="nt">li</span><span class="p">></span>Sender is required.<span class="p"></</span><span class="nt">li</span><span class="p">></span> <span class="p"></</span><span class="nt">ul</span><span class="p">></span> |
Список имеет класс CSS “errorlist”, чтобы вы могли стилизовать его внешний вид. Если вы хотите дополнительно настроить отображение ошибок, вы можете сделать это, зациклив их:
1 2 3 4 5 6 7 |
<span class="cp">{%</span> <span class="k">if</span> <span class="nv">form.subject.errors</span> <span class="cp">%}</span> <span class="p"><</span><span class="nt">ol</span><span class="p">></span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">error</span> <span class="k">in</span> <span class="nv">form.subject.errors</span> <span class="cp">%}</span> <span class="p"><</span><span class="nt">li</span><span class="p">><</span><span class="nt">strong</span><span class="p">></span><span class="cp">{{</span> <span class="nv">error</span><span class="o">|</span><span class="nf">escape</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">strong</span><span class="p">></</span><span class="nt">li</span><span class="p">></span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> <span class="p"></</span><span class="nt">ol</span><span class="p">></span> <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> |
Ошибки не связанные с полями (и / или скрытые ошибки полей, которые отображаются в верхней части формы при использовании таких помощников, как form.as_p ()), будут отображаться с дополнительным классом nonfield
, чтобы помочь отличить их от ошибок, специфичных для поля. Например, {{form.non_field_errors}} будет выглядеть так:
1 2 3 |
<span class="p"><</span><span class="nt">ul</span> <span class="na">class</span><span class="o">=</span><span class="s">"errorlist nonfield"</span><span class="p">></span> <span class="p"><</span><span class="nt">li</span><span class="p">></span>Generic validation error<span class="p"></</span><span class="nt">li</span><span class="p">></span> <span class="p"></</span><span class="nt">ul</span><span class="p">></span> |
Цикл по полям формы
Если вы используете один и тот же HTML-код для каждого поля формы, вы можете уменьшить количество дублирующегося кода, по очереди просматривая каждое поле, используя цикл {% for%}:
1 2 3 4 5 6 7 8 9 |
<span class="cp">{%</span> <span class="k">for</span> <span class="nv">field</span> <span class="k">in</span> <span class="nv">form</span> <span class="cp">%}</span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"fieldWrapper"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">field.errors</span> <span class="cp">}}</span> <span class="cp">{{</span> <span class="nv">field.label_tag</span> <span class="cp">}}</span> <span class="cp">{{</span> <span class="nv">field</span> <span class="cp">}}</span> <span class="cp">{%</span> <span class="k">if</span> <span class="nv">field.help_text</span> <span class="cp">%}</span> <span class="p"><</span><span class="nt">p</span> <span class="na">class</span><span class="o">=</span><span class="s">"help"</span><span class="p">></span><span class="cp">{{</span> <span class="nv">field.help_text</span><span class="o">|</span><span class="nf">safe</span> <span class="cp">}}</span><span class="p"></</span><span class="nt">p</span><span class="p">></span> <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> |
Полезные атрибуты {{field}} включают в себя:
- {{field.label}} – Метка поля, например, “Адрес электронной почты”.
- {{field.label_tag}} – Метка поля обернута в соответствующий тег HTML <label>. Это включает в себя label_suffix формы. Например, по умолчанию label_suffix – это двоеточие:
1<span class="o"><</span><span class="n">label</span> <span class="k">for</span><span class="o">=</span><span class="s2">"id_email"</span><span class="o">></span><span class="n">Email</span> <span class="n">address</span><span class="p">:</span><span class="o"></</span><span class="n">label</span><span class="o">></span>
- {{field.id_for_label}} – Идентификатор, который будет использоваться для этого поля (id_email в примере выше). Если вы создаете метку вручную, вы можете использовать ее вместо label_tag. Это также полезно, например, если у вас есть некоторый встроенный JavaScript и вы хотите избежать жесткого кодирования ID поля.
- {{field.value}} – Значение поля. например, somebody@example.com.
- {{field.html_name}} – Имя поля, которое будет использоваться в поле имени элемента ввода. При этом учитывается префикс формы, если он был установлен.
- {{field.help_text}} – Любой текст справки, который был связан с полем.
- {{field.errors}} – Выводит <ul class = “errorlist”>, содержащий любые ошибки проверки, соответствующие этому полю. Вы можете настроить представление ошибок с помощью цикла {% for error в field.errors%}. В этом случае каждый объект в цикле является строкой, содержащей сообщение об ошибке.
- {{field.is_hidden}} – Этот атрибут имеет значение True, если поле формы является скрытым полем, и False в противном случае. Он не особенно полезен в качестве переменной шаблона, но может быть полезен в условных тестах, таких как:
123<span class="cp">{%</span> <span class="k">if</span> <span class="nv">field.is_hidden</span> <span class="cp">%}</span><span class="c">{# Do something special #}</span><span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
- {{field.field}} – Экземпляр Field из класса формы, который упаковывает этот BoundField. Вы можете использовать его для доступа к атрибутам поля, например, {{char_field.field.max_length}}.
Зацикливание на скрытых и видимых полях
Если вы вручную размещаете форму в шаблоне, а не полагаетесь на макет формы по умолчанию в Django, вам может потребоваться обрабатывать поля <input type = “hidden”> иначе, чем не скрытые поля. Например, поскольку скрытые поля ничего не отображают, размещение сообщений об ошибках рядом с полем может привести к путанице для ваших пользователей, поэтому ошибки для этих полей следует обрабатывать по-разному.
Django предоставляет два метода в форме, которые позволяют вам перебирать скрытые и видимые поля независимо: hidden_fields () и visible_fields (). Вот модификация более раннего примера, который использует эти два метода:
1 2 3 4 5 6 7 8 9 10 11 |
<span class="c">{# Include the hidden fields #}</span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">hidden</span> <span class="k">in</span> <span class="nv">form.hidden_fields</span> <span class="cp">%}</span> <span class="cp">{{</span> <span class="nv">hidden</span> <span class="cp">}}</span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> <span class="c">{# Include the visible fields #}</span> <span class="cp">{%</span> <span class="k">for</span> <span class="nv">field</span> <span class="k">in</span> <span class="nv">form.visible_fields</span> <span class="cp">%}</span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"fieldWrapper"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">field.errors</span> <span class="cp">}}</span> <span class="cp">{{</span> <span class="nv">field.label_tag</span> <span class="cp">}}</span> <span class="cp">{{</span> <span class="nv">field</span> <span class="cp">}}</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> |
Этот пример не обрабатывает никаких ошибок в скрытых полях. Обычно ошибка в скрытом поле является признаком подделки формы, так как нормальное взаимодействие формы не изменит их. Тем не менее, вы также можете легко вставить некоторые сообщения об ошибках для этих ошибок формы.
Многоразовые шаблоны форм
Если ваш сайт использует одну и ту же логику рендеринга для форм в нескольких местах, вы можете уменьшить дублирование, сохранив цикл формы в автономном шаблоне и используя тег include для повторного использования в других шаблонах:
1 2 3 4 5 6 7 8 9 10 |
# In your form template: <span class="cp">{%</span> <span class="k">include</span> <span class="s2">"form_snippet.html"</span> <span class="cp">%}</span> # In form_snippet.html: <span class="cp">{%</span> <span class="k">for</span> <span class="nv">field</span> <span class="k">in</span> <span class="nv">form</span> <span class="cp">%}</span> <span class="p"><</span><span class="nt">div</span> <span class="na">class</span><span class="o">=</span><span class="s">"fieldWrapper"</span><span class="p">></span> <span class="cp">{{</span> <span class="nv">field.errors</span> <span class="cp">}}</span> <span class="cp">{{</span> <span class="nv">field.label_tag</span> <span class="cp">}}</span> <span class="cp">{{</span> <span class="nv">field</span> <span class="cp">}}</span> <span class="p"></</span><span class="nt">div</span><span class="p">></span> <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> |
Если объект формы, переданный шаблону, имеет другое имя в контексте, вы можете присвоить ему псевдоним, используя аргумент with тега include:
1 |
<span class="cp">{%</span> <span class="k">include</span> <span class="s2">"form_snippet.html"</span> <span class="k">with</span> <span class="nv">form</span><span class="o">=</span><span class="nv">comment_form</span> <span class="cp">%}</span> |
Если вы обнаружите, что делаете это часто, вы можете создать собственный тег включения.