About this document
Этот документ знакомит со способами работы с формами. Для более детальной информации по API форм обращайтесь к API форм, Поля формы и Проверка форм и полей формы.
django.forms - библиотека для работы с формами.
Несмотря на наличие возможности обработки форм через обычный класс Django HttpRequest, использование специализированной библиотеки предоставляет решение для общих задач, возникающих при работе с формами, например:
Автоматически генерировать HTML код формы с использованием необходимых виджетов.
Проверять переданную информацию с помощью набора правил валидации.
Заново отображать форму при обнаружении ошибок.
Преобразовывать переданную информацию в соответствующие типы данных языка Python.
Библиотека работает с нижеперечисленными сущностями:
Класс, который соответствует определённому HTML-коду т.е. <input type="text"> или <textarea>. Он реализует генерацию HTML-кода для виджета.
Класс, который отвечает за проведение валидации, т.е. EmailField обеспечивает получение правильного адреса электронной почты.
Коллекция полей, которые знают как проверять введённую информацию и отображать себя в виде HTML кода.
Ресурсы CSS и JavaScript, которые необходимы для правильного отображения формы.
Эта библиотека отделена от остальных компонентов Django, таких как слой взаимодействия с базой данных, представления и шаблоны. Оно зависит только от настроек Django, ряда вспомогательных функций из django.utils и механизма интернационализации (необязательная зависимость).
Объект формы содержит в себе последовательность полей формы и коллекцию правил валидации, которые должны быть пройдены для того, чтобы форма приняла переданную информацию. Классы форм создаются как подклассы django.forms.Form и используют декларативный стиль, аналогичный используемому в моделях Django.
Например, рассмотрим форму, созданную для реализации функционала “свяжитесь со мной” на личном веб сайте:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)
Форма составлена из объектов Field. В нашем случае, форма содержит четыре поля: subject, message, sender и cc_myself. CharField, EmailField и BooleanField - это просто три стандартных типа поля; полный список полей может быть найден в Поля формы.
Если ваша форма будет использоваться для прямого доступа к модели Django, вы можете использовать ModelForm, чтобы исключить дублирование описания вашей модели.
Стандартный шаблон для работы с формой в представлении выглядит следующим образом:
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
if form.is_valid(): # All validation rules pass
# Process the data in form.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
form = ContactForm() # An unbound form
return render(request, 'contact.html', {
'form': form,
})
В этом коде заложено три сценария:
Форма отправлена? |
Данные |
Что происходит |
|---|---|---|
Не отправлена |
Ещё нет |
Шаблон получает пустой экземпляр ContactForm. |
Отправлена |
Неверные данные |
Шаблон получает заполненный экземпляр ContactForm. |
Отправлена |
Правильные данные |
Данные обрабатываются. Перенаправление на страницу с “благодарностями”. |
Важно понимать разницу между Заполненные и незаполненные формы:
Незаполненная форма не содержит данных, привязанных к её полям. При отображении формы пользователь увидит её пустой или содержащей значения по умолчанию.
Заполненная форма содержит переданную информацию и, следовательно, может быть использована для проверки введённых данных. При отображении заполненной формы, не прошедшей проверку, она будет содержать встроенные сообщения об ошибках, которые расскажут пользователю о причинах отказа в принятии его данных.
Чтобы узнать как обрабатывать загрузку файлов через форму, обратитесь к Привязка загруженных файлов к форме.
Если is_valid() возвратила True, то проверенные данные будут располагаться в словаре form.cleaned_data. Все значения этого словаря приведены к соответствующему типу данных.
Примечание
Также вы можете напрямую обратиться к непроверенным данным через request.POST, но лучше использовать проверенные данные.
В приведённом ранее примере, cc_myself будет булевым значением. Аналогично, такие поля как IntegerField и FloatField преобразовывают свои значения в типы Python int и float соответственно.
Поля “только для чтения” не доступны через form.cleaned_data (и установка значения в собственном методе clean() не даст никакого эффекта). Такие поля отображаются в виде текста, а не в виде элемента ввода и, следовательно, не отправляются на сервер.
Продолжая работать над предыдущим примером, покажем, как могут быть обработаны данные из формы:
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself']
recipients = ['info@example.com']
if cc_myself:
recipients.append(sender)
from django.core.mail import send_mail
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/') # Redirect after POST
Совет
Подробную информацию про отправку электронной почты с помощью Django можно найти в Sending email.
Формы разработаны для работы с шаблонным языком Django. В приведённом ранее примере мы передавали экземпляр ContactForm в шаблон, используя контекстную переменную form. Покажем простой пример шаблона:
<form action="/contact/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
Форма просто выводит свои поля. Указание тега <form> и кнопки для отправки формы - это ваша задача.
Если ваша форма содержит загружаемые файлы, удостоверьтесь, что элемент form имеет атрибут enctype="multipart/form-data". Если вам потребуется создать общий шаблон, не зависящий от наличия функционала загрузки файлов, вы можете использовать атрибут формы is_multipart():
<form action="/contact/" method="post"
{% if form.is_multipart %}enctype="multipart/form-data"{% endif %}>
Forms and Cross Site Request Forgery protection
Django поставляется с защитой против Cross Site Request Forgeries. Для отправки формы через POST при включенной защите от CSRF вы должны использовать шаблонный тег csrf_token, как показано в предыдущем примере. Тем не менее, раз CSRF-защита не обязательна для применения в шаблонах при оформлении формы, этот тег опущен в последующих примерах.
Тег form.as_p выводит поля формы в виде параграфов (т.е. <p/>) вместе с соответствующими метками. Ниже представлены пример с результатом использования нашего шаблона:
<form action="/contact/" method="post">
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" /></p>
<p><label for="id_message">Message:</label>
<input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
<input type="submit" value="Submit" />
</form>
Следует отметить, что каждое поле формы обладает атрибутом с идентификатором id_<field-name>, с помощью которого обеспечивается связь с тегом метки. Это позволяет формам быть дружественными к вспомогательным технологиям, например, это поможет работе ПО для слепых. Также вы можете настроить способ генерации меток и идентификаторов.
Вы можете использовать form.as_table для вывода полей формы в виде таблицы (потребуется прописать в шаблоне теги <table>) и form.as_ul для вывода полей формы в виде элементов списка.
Если сгенерированный по умолчанию HTML не подходит для решения вашей задачи, вы можете изменить представление формы с помощью шаблонного языка Django. Продолжая работу с приведённым ранее примером:
<form action="/contact/" method="post">
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.subject.errors }}
<label for="id_subject">Email subject:</label>
{{ form.subject }}
</div>
<div class="fieldWrapper">
{{ form.message.errors }}
<label for="id_message">Your message:</label>
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="id_sender">Your email address:</label>
{{ form.sender }}
</div>
<div class="fieldWrapper">
{{ form.cc_myself.errors }}
<label for="id_cc_myself">CC yourself?</label>
{{ form.cc_myself }}
</div>
<p><input type="submit" value="Send message" /></p>
</form>
Каждое именованное поле формы может быть выведено в шаблоне с помощью тега {{ form.name_of_field }}, который создаст HTML-код, необходимый для отображения виджета. Использование тега {{ form.name_of_field.errors }} отобразит список ошибок поля формы в виде ненумерованного списка. Результат может быть таким:
<ul class="errorlist">
<li>Sender is required.</li>
</ul>
Списку назначен CSS-класс errorlist, что позволяет вам настроить параметры его отображения. Если потребуется более тонкая настройка отображения ошибок, вы можете это организовать с помощью цикла по ним:
{% if form.subject.errors %}
<ol>
{% for error in form.subject.errors %}
<li><strong>{{ error|escape }}</strong></li>
{% endfor %}
</ol>
{% endif %}
Если вы используете однотипный HTML для каждого поля формы, вы можете избежать дублирования кода, используя тег {% for %} для прохода по полям формы:
<form action="/contact/" method="post">
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Send message" /></p>
</form>
Внутри цикла тег {{ field }} представляет собой экземпляр класса BoundField. Класс BoundField также имеет приведённые далее атрибуты, которые могут быть полезны в ваших шаблонах:
Метка поля, т.е. Email address.
Метка поля обёрнута в соответствующий HTML-тег <label>.
This includes the form’s label_suffix. For example, the default label_suffix is a colon:
<label for="id_email">Email address:</label>
ID, которое будет использоваться для этого поля (id_email в примере выше). Вы можете использовать его вместо label_tag, если самостоятельно генерируете <label> для поля. Так полезно при генерации JavaScript, если вы не хотите “хардкодить” ID.
Значение поля, т.е. someone@example.com.
Имя поля, которое будет использовано в HTML-поле. Здесь учитывается префикс формы, если он был установлен.
Любой вспомогательный текст, который привязан к полю.
Вывод <ul class="errorlist">, содержащий все ошибки валидации, относящиеся к полю. Вы можете настраивать представление списка ошибок с помощью цикла {% for error in field.errors %}. В этом случае, каждый объект в цикле является простой строкой, содержащей сообщение об ошибке.
Значение этого атрибута равно True, если поле является скрытым, и False в противном случае. Данный атрибут обычно не используется при выводе формы, но может быть полезен в условиях подобных этому:
{% if field.is_hidden %}
{# Do something special #}
{% endif %}
Экземпляр Field из класса формы, который обёрнут с помощью BoundField. Он предоставляет доступ к атрибутам Field, т.е. {{ char_field.field.max_length }}.
Если на вашем сайте используется однотипная логика отображения форм, вы можете избежать дублирования кода, сохранив цикл по полям формы в отдельном шаблоне и подключая его в другие шаблоны с помощью тега include:
<form action="/contact/" method="post">
{% include "form_snippet.html" %}
<p><input type="submit" value="Send message" /></p>
</form>
# In form_snippet.html:
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
</div>
{% endfor %}
Если объект формы, переданный в шаблон, имеет другое имя в контексте, вы можете создать для него псевдоним, используя аргумент with тега include:
<form action="/comments/add/" method="post">
{% include "form_snippet.html" with form=comment_form %}
<p><input type="submit" value="Submit comment" /></p>
</form>
Если вам придётся делать такое часто, то можно создать собственный включающий тег.
Мы рассмотрели базовые возможности форм, но они могут больше:
См.также
Предоставляет полный справочник на API, включая поля, виджеты и валидацию как полей, так и формы.
Mar 30, 2016