About this document
Этот документ знакомит со способами работы с формами. Для более детальной информации по API форм обращайтесь к API форм, Поля формы и Проверка форм и полей формы.
django.forms – библиотека для работы с формами.
Несмотря на наличие возможности обработки форм через обычный класс Django HttpRequest, использование специализированной библиотеки предоставляет решение для общих задач, возникающих при работе с формами. Используя библиотек, вы можете:
Библиотека работает с нижеперечисленными сущностями:
Эта библиотека отделена от остальных компонентов 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 objects. В нашем случае, форма содержит четыре поля: subject, message, sender и cc_myself. CharField, EmailField и BooleanField – это просто три стандартных типа поля; полный список полей может быть найден в Поля формы.
Если ваша форма будет использоваться для прямого доступа к модели Django, вы можете использовать ModelForm, чтобы исключить дублирование описания вашей модели.
Стандартный шаблон для работы с формой в представлении выглядит следующим образом:
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_to_response('contact.html', {
'form': form,
})
В этом коде заложено три сценария:
Различие между заполненной и незаполненной формами имеет большое значение. Незаполненная форма не содержит информации, при её отображении пользователю, она будет пустой или будет содержать значения по умолчанию. Заполненная форма содержит переданную информацию и, следовательно, может быть использована для проверки введённых данных. При отображении заполненной формы, не прошедшей проверку, она будет содержать встроенные сообщения об ошибках, которые расскажут пользователю о причинах отказа в принятии его данных.
Обратитесь к Заполненные и незаполненные формы для подробной информации по различиям между заполненной и незаполненной формами.
Чтобы узнать как обрабатывать закачку файла через форму обратитесь к Привязка загруженных файлов к форме.
После того, как is_valid() возвратила True, вы можете спокойно работать с полученными данными, зная, что они прошли валидацию в вашей форме. Несмотря на наличие прямого доступа к request.POST, рекомендуется использовать form.cleaned_data. Данные, представленные этой структурой не только проверены, но и преобразованы в соответствующие типы языка Python. В приведённом выше примере, cc_myself представлено булевым значением. Аналогично, поля, подобные IntegerField и FloatField преобразуют значения в типы int и float соответственно. Следует отметить, что нередактируемые поля (readonly) не представлены 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> и кнопки для отправки формы – это ваша задача.
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="text" 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 также имеет приведённые далее атрибуты, которые могут быть полезны в вашем шаблоне:
Значение этого атрибута равно True, если поля является скрытым, и False в противном случае. Данный атрибут обычно не используется при выводе формы, но может быть полезен в условиях подобных этому:
{% if field.is_hidden %}
{# Do something special #}
{% endif %}
Если на вашем сайте используется однотипная логика отображения форм, вы можете избежать дублирования кода, сохранив цикл по полям формы в отдельном шаблоне и подключая его в другие шаблоны с помощью тага 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>
Если вам придётся делать такое часто, то можно создать собственный включающий таг.
Мы рассмотрели базовые возможности форм, но они могут больше:
См.также
Aug 21, 2013