API форм
О документе
Этот документ описывает подробности API форм Django. Сначала прочтите введение в работу с формами.
Связанные и несвязанные формы
Экземпляр Form может быть связан с набором данных или несвязан.
- Если он связан с набором данных, он может валидировать эти данные и отобразить форму в HTML с отображенными данными.
- Если он несвязан, он не может выполнить валидацию (потому что нет данных для валидации!), но он все равно может отобразить пустую форму в HTML.
-
class Form[source]
Чтобы создать экземпляр несвязанной Form, просто создайте экземпляр класса:
>>> f = ContactForm()
Чтобы связать данные с формой, передайте данные в виде словаря в качестве первого параметра конструктору класса Form:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
В этом словаре ключи — имена полей, которые соответствуют атрибутам в вашем классе Form. Значения — это данные, которые вы хотите валидировать. Обычно это строки, но нет требования, чтобы они были строками; тип данных, который вы передаете, зависит от Field, как мы увидим чуть позже.
-
Form.is_bound
Если вам нужно отличить связанные и несвязанные экземпляры форм во время выполнения, проверьте значение атрибута формы is_bound:
>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({'subject': 'hello'})
>>> f.is_bound
True
Обратите внимание, что передача пустого словаря создает связанную форму с пустыми данными:
>>> f = ContactForm({})
>>> f.is_bound
True
Если у вас есть связанный экземпляр Form и вы хотите как-то изменить данные или хотите связать несвязанный экземпляр Form с данными, создайте другой экземпляр Form. Нет способа изменить данные в экземпляре Form. После создания экземпляра Form следует считать его данные неизменяемыми, независимо от того, есть ли у него данные или нет.
Использование форм для проверки данных
-
Form.clean()
Реализуйте метод clean() в вашем классе Form, когда необходимо добавить пользовательскую проверку для полей, которые взаимозависимы. См. Очистка и проверка полей, зависящих друг от друга для примера использования.
-
Form.is_valid()
Основная задача объекта Form — проверка данных. Для связанного экземпляра Form вызовите метод is_valid() для запуска проверки и возврата булевого значения, указывающего, были ли данные валидны:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
Давайте попробуем с невалидными данными. В этом случае subject пустое (ошибка, потому что все поля по умолчанию обязательны), а sender не является допустимым адресом электронной почты:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid email address',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
-
Form.errors
Получите доступ к атрибуту errors, чтобы получить словарь сообщений об ошибках:
>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}
В этом словаре ключи — имена полей, а значения — списки строк, представляющих сообщения об ошибках. Сообщения об ошибках хранятся в списках, потому что у поля может быть несколько сообщений об ошибках.
Вы можете получить доступ к errors, не вызывая сначала is_valid(). Данные формы будут проверены в первый раз, когда вы либо вызовете is_valid(), либо получите доступ к errors.
Процедуры проверки данных будут вызваны только один раз, независимо от того, сколько раз вы получаете доступ к errors или вызываете is_valid(). Это означает, что если проверка имеет побочные эффекты, эти побочные эффекты будут вызваны только один раз.
-
Form.errors.as_data()
Возвращает словарь, сопоставляющий поля с их исходными dict экземплярами.
>>> f.errors.as_data()
{'sender': [ValidationError(['Enter a valid email address.'])],
'subject': [ValidationError(['This field is required.'])]}
Используйте этот метод всякий раз, когда вам нужно идентифицировать ошибку по ее code. Это позволяет переписывать сообщение об ошибке или писать пользовательскую логику в представлении, когда присутствует определенная ошибка. Также его можно использовать для сериализации ошибок в пользовательском формате (например, XML); например, as_json() использует as_data().
Необходимость метода as_data() обусловлена обратной совместимостью. Ранее экземпляры ValidationError терялись сразу после добавления их отображенных сообщений об ошибках в словарь Form.errors. В идеале Form.errors должен был хранить экземпляры ValidationError, а методы с префиксом as_ могли бы их отображать, но это пришлось сделать наоборот, чтобы не сломать код, который ожидает отображенные сообщения об ошибках в Form.errors.
-
Form.errors.as_json(escape_html=False)
Возвращает сериализованные ошибки в формате JSON.
>>> f.errors.as_json()
{"sender": [{"message": "Enter a valid email address.", "code": "invalid"}],
"subject": [{"message": "This field is required.", "code": "required"}]}
По умолчанию as_json() не экранирует свой вывод. Если вы используете его для чего-то вроде запросов AJAX в представление формы, где клиент интерпретирует ответ и вставляет ошибки в страницу, вам следует убедиться, что результаты экранированы на стороне клиента, чтобы избежать возможности атаки типа межсайтовый скриптинг. Это тривиально сделать с помощью JavaScript-библиотеки, такой как jQuery — просто используйте $(el).text(errorText) вместо .html().
Если по какой-то причине вы не хотите использовать экранирование на стороне клиента, вы также можете установить escape_html=True, и сообщения об ошибках будут экранированы, так что вы можете использовать их непосредственно в HTML.
-
Form.errors.get_json_data(escape_html=False)
Возвращает ошибки в виде словаря, подходящего для сериализации в JSON. Form.errors.as_json() возвращает сериализованный JSON, в то время как этот возвращает данные об ошибках до сериализации.
Параметр escape_html ведет себя так, как описано в Form.errors.as_json().
-
Form.add_error(field, error)
Этот метод позволяет добавлять ошибки к определенным полям изнутри метода Form.clean() или извне формы; например, из представления.
Аргумент field — имя поля, к которому следует добавить ошибки. Если его значение None, ошибка будет обработана как ошибка не связанная с полем, как возвращается Form.non_field_errors().
Аргумент error может быть простой строкой или, что предпочтительнее, экземпляром ValidationError. См. Вызов ValidationError для наилучших практик определения ошибок формы.
Обратите внимание, что Form.add_error() автоматически удаляет соответствующее поле из cleaned_data.
-
Form.has_error(field, code=None)
Этот метод возвращает булево значение, обозначающее, есть ли у поля ошибка со специфическим сообщением об ошибке code. Если code равно None, он вернет True , если поле содержит какие-либо ошибки вообще.
Для проверки ошибок, не связанных с полем, используйте NON_FIELD_ERRORS в качестве параметра field.
-
Form.non_field_errors()
Этот метод возвращает список ошибок из Form.errors, которые не связаны с каким-либо конкретным полем. Это включает ошибки, которые вызваны в Form.clean(), и ошибки, добавленные с помощью Form.add_error(None,
"...").
Поведение несвязанных форм
Проверка формы без данных бессмысленна, но для справки вот что происходит со несвязанными формами:
>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
Динамические начальные значения
-
Form.initial
Используйте initial, чтобы объявить начальное значение полей формы во время выполнения. Например, вы можете заполнить поле username именем пользователя текущей сессии.
Для этого используйте аргумент initial для Form. Этот аргумент, если задан, должен быть словарем, сопоставляющим имена полей с начальными значениями. Включайте только те поля, для которых вы задаёте начальное значение; нет необходимости включать каждое поле вашей формы. Например:
>>> f = ContactForm(initial={'subject': 'Hi there!'})
Эти значения отображаются только для не связанных форм, и они не используются в качестве значений по умолчанию, если конкретное значение не указано.
Если Field определяет initial и вы включаете initial при создании экземпляра Form, то последнее initial будет иметь приоритет. В этом примере initial задано как на уровне поля, так и на уровне экземпляра формы, и приоритет имеет последнее:
>>> from django import forms
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial='class')
... url = forms.URLField()
... comment = forms.CharField()
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="instance" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" required></td></tr>
-
Form.get_initial_for_field(field, field_name)
Используйте get_initial_for_field() для получения начальных данных для поля формы. Оно получает данные из Form.initial и Field.initial в указанном порядке и вычисляет любые вызываемые начальные значения.
Проверка изменения данных формы
-
Form.has_changed()
Используйте метод has_changed() для вашей Form, когда вам нужно проверить, были ли данные формы изменены с момента начальных данных.
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data, initial=data)
>>> f.has_changed()
False
При отправке формы мы реконструируем её и предоставляем исходные данные, чтобы можно было провести сравнение:
>>> f = ContactForm(request.POST, initial=data) >>> f.has_changed()
has_changed() будет True, если данные из request.POST отличаются от тех, что были предоставлены в initial, или False в противном случае. Результат вычисляется путём вызова Field.has_changed() для каждого поля в форме.
-
Form.changed_data
Атрибут changed_data возвращает список имён полей, значения которых в связанных данных формы (обычно request.POST) отличаются от предоставленных в initial. Он возвращает пустой список, если данные не отличаются.
>>> f = ContactForm(request.POST, initial=data)
>>> if f.has_changed():
... print("The following fields changed: %s" % ", ".join(f.changed_data))
Доступ к полям из формы
-
Form.fields
Вы можете получить доступ к полям экземпляра Form через его атрибут fields.
>>> for row in f.fields.values(): print(row) ... <django.forms.fields.CharField object at 0x7ffaac632510> <django.forms.fields.URLField object at 0x7ffaac632f90> <django.forms.fields.CharField object at 0x7ffaac3aa050> >>> f.fields['name'] <django.forms.fields.CharField object at 0x7ffaac6324d0>
Вы можете изменить поле экземпляра Form, чтобы изменить способ его отображения в форме.
>>> f.as_table().split('\n')[0]
'<tr><th>Name:</th><td><input name="name" type="text" value="instance" required></td></tr>'
>>> f.fields['name'].label = "Username"
>>> f.as_table().split('\n')[0]
'<tr><th>Username:</th><td><input name="name" type="text" value="instance" required></td></tr>'
Будьте осторожны, не изменяйте атрибут base_fields, так как это изменение повлияет на все последующие экземпляры ContactForm в пределах того же процесса Python:
>>> f.base_fields['name'].label = "Username"
>>> another_f = CommentForm(auto_id=False)
>>> another_f.as_table().split('\n')[0]
'<tr><th>Username:</th><td><input name="name" type="text" value="class" required></td></tr>'
Доступ к «очищенным» данным
-
Form.cleaned_data
Каждое поле класса Form отвечает не только за валидацию данных, но и за их «очистку» — приведение к согласованному формату. Это полезная функция, так как она позволяет вводить данные для конкретного поля различными способами, всегда получая согласованный результат.
Например, DateField нормализует ввод в объект Python datetime.date. Независимо от того, передаёте ли вы строку в формате '1994-07-15', объект datetime.date или другие форматы, DateField всегда нормализует его в объект datetime.date при условии его валидности.
После создания экземпляра Form с набором данных и его проверки вы можете получить доступ к чистым данным через его атрибут cleaned_data:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
Обратите внимание, что любое текстовое поле — например, CharField или EmailField — всегда очищает ввод в строку. Мы рассмотрим последствия кодировки позже в этом документе.
Если ваши данные не проходят валидацию, словарь cleaned_data содержит только валидные поля:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid email address',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there'}
cleaned_data всегда только содержит ключ для полей, определённых в Form, даже если вы передаёте дополнительные данные при определении Form. В этом примере мы передаём несколько дополнительных полей конструктору ContactForm, но cleaned_data содержит только поля формы.
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True,
... 'extra_field_1': 'foo',
... 'extra_field_2': 'bar',
... 'extra_field_3': 'baz'}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
Когда Form валиден, cleaned_data будет содержать ключ и значение для всех его полей, даже если данные не содержали значения для некоторых необязательных полей. В этом примере словарь данных не содержит значения для поля nick_name, но cleaned_data включает его со значением по умолчанию (пустой строкой):
>>> from django import forms
>>> class OptionalPersonForm(forms.Form):
... first_name = forms.CharField()
... last_name = forms.CharField()
... nick_name = forms.CharField(required=False)
>>> data = {'first_name': 'John', 'last_name': 'Lennon'}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}
В этом примере значение cleaned_data для nick_name установлено в пустую строку, потому что nick_name — CharField, а CharField обрабатывают пустые значения как пустую строку. Каждый тип поля знает, какое значение «пустое» — например, для DateField это None вместо пустой строки. Для подробной информации о поведении каждого поля в этом случае см. примечание «Пустое значение» для каждого поля в разделе «Встроенные Field классы» ниже.
Вы можете написать код для проверки определённых полей формы (по их имени) или формы в целом (учитывая сочетание различных полей). Более подробная информация об этом содержится в Валидация форм и полей.
Вывод форм в HTML
Вторая задача объекта Form — это визуализация себя в HTML. Для этого просто вызовите метод print:
>>> f = ContactForm() >>> print(f) <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr> <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr> <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr> <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>
Если форма связана с данными, HTML-вывод будет содержать эти данные должным образом. Например, если поле представлено <input type="text">, данные будут в атрибуте value. Если поле представлено <input type="checkbox">, HTML-вывод будет содержать checked, если это необходимо:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" value="foo@example.com" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked></td></tr>
Этот вывод по умолчанию — HTML-таблица из двух столбцов, с полем для каждого поля. Обратите внимание на следующее:
- Для гибкости вывод не включает теги
<table>и</table>, а также теги<form>и</form>или тег<input type="submit">. Вы должны это сделать сами. - Каждый тип поля имеет стандартное HTML-представление.
CharFieldпредставлен тегом<input type="text">, аEmailField— тегом<input type="email">.BooleanFieldпредставлен тегом<input type="checkbox">. Это всего лишь разумные значения по умолчанию; вы можете указать используемый HTML для данного поля, используя виджеты, которые будут объяснены позже. - HTML-тег
nameдля каждого тега берется напрямую из имени атрибута в классеContactForm. - Текст метки для каждого поля — например,
'Subject:','Message:'и'Cc myself:'генерируется из имени поля путём преобразования всех символов нижнего подчеркивания в пробелы и прописных первых букв. Опять же, это всего лишь разумные значения по умолчанию; вы также можете задать метки вручную. - Каждая метка окружена HTML-тегом
<label>, который ссылается на соответствующее поле формы через егоid. В свою очередь, егоidгенерируется путём добавления'id_'к имени поля. Атрибутыidи теги<label>включаются в выходные данные по умолчанию, чтобы следовать лучшим практикам, но вы можете изменить это поведение. - Вывод использует синтаксис HTML5, ориентируясь на
<!DOCTYPE html>. Например, он использует булевы атрибуты, такие какchecked, вместо XHTML-стиляchecked='checked'.
Хотя вывод <table> — это стиль вывода по умолчанию при выводе формы, доступны другие стили вывода. Каждый стиль доступен как метод объекта формы, и каждый метод визуализации возвращает строку.
as_p()
-
Form.as_p()
as_p() визуализирует форму как набор тегов <p>, где каждый <p> содержит одно поле.
>>> f = ContactForm() >>> f.as_p() '<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" required></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>' >>> print(f.as_p()) <p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p> <p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p> <p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></p> <p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>
as_ul()
-
Form.as_ul()
as_ul() визуализирует форму как набор тегов <li>, где каждый <li> содержит одно поле. Он не включает <ul> или </ul>, чтобы вы могли указать любые HTML-атрибуты в <ul> для гибкости:
>>> f = ContactForm() >>> f.as_ul() '<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>' >>> print(f.as_ul()) <li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li> <li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li> <li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li> <li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>
as_table()
-
Form.as_table()
Наконец, as_table() визуализирует форму в виде HTML-таблицы <table>. Это точно так же, как print. На самом деле, при визуализации объекта формы он вызывает свой метод as_table() в фоновом режиме:
>>> f = ContactForm() >>> f.as_table() '<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>' >>> print(f) <tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr> <tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr> <tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr> <tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>
Стиль необходимых или ошибочных строк формы
-
Form.error_css_class
-
Form.required_css_class
Довольно распространённый подход — стилизовать строки и поля форм, которые обязательны для заполнения или содержат ошибки. Например, вы можете отображать обязательные строки формы жирным шрифтом и выделять ошибки красным цветом.
Класс Form имеет несколько крючков, которые можно использовать для добавления атрибутов class к обязательным строкам или строкам с ошибками: просто задайте атрибуты Form.error_css_class и/или Form.required_css_class:
from django import forms
class ContactForm(forms.Form):
error_css_class = 'error'
required_css_class = 'required'
# ... and the rest of your fields here
После этого строки получат классы "error" и/или "required", по мере необходимости. HTML будет выглядеть примерно так:
>>> f = ContactForm(data)
>>> print(f.as_table())
<tr class="required"><th><label class="required" for="id_subject">Subject:</label> ...
<tr class="required"><th><label class="required" for="id_message">Message:</label> ...
<tr class="required error"><th><label class="required" for="id_sender">Sender:</label> ...
<tr><th><label for="id_cc_myself">Cc myself:<label> ...
>>> f['subject'].label_tag()
<label class="required" for="id_subject">Subject:</label>
>>> f['subject'].label_tag(attrs={'class': 'foo'})
<label for="id_subject" class="foo required">Subject:</label>
Настройка HTML-атрибутов и тегов элементов формы id
-
Form.auto_id
По умолчанию методы рендеринга формы включают:
- HTML-атрибуты
idна элементах формы. - Соответствующие теги
<label>вокруг меток. HTML-тег<label>указывает, какой текст метки связан с каким элементом формы. Такое небольшое улучшение делает формы более удобными и доступными для устройств с помощниками. Всегда рекомендуется использовать теги<label>.
Значения атрибута id генерируются путём добавления префикса id_ к именам полей формы. Однако это поведение настраивается, если вы хотите изменить соглашение id или полностью убрать HTML-атрибуты id и теги <label>.
Используйте аргумент auto_id в конструкторе Form для управления поведением id и меток. Этот аргумент должен быть True, False или строкой.
Если auto_id равно False, вывод формы не будет содержать теги <label> ни атрибутов id:
>>> f = ContactForm(auto_id=False) >>> print(f.as_table()) <tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" required></td></tr> <tr><th>Message:</th><td><input type="text" name="message" required></td></tr> <tr><th>Sender:</th><td><input type="email" name="sender" required></td></tr> <tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself"></td></tr> >>> print(f.as_ul()) <li>Subject: <input type="text" name="subject" maxlength="100" required></li> <li>Message: <input type="text" name="message" required></li> <li>Sender: <input type="email" name="sender" required></li> <li>Cc myself: <input type="checkbox" name="cc_myself"></li> >>> print(f.as_p()) <p>Subject: <input type="text" name="subject" maxlength="100" required></p> <p>Message: <input type="text" name="message" required></p> <p>Sender: <input type="email" name="sender" required></p> <p>Cc myself: <input type="checkbox" name="cc_myself"></p>
Если auto_id установлено в значение True, вывод формы будет содержать теги <label> и будет просто использовать имя поля в качестве id для каждого поля формы:
>>> f = ContactForm(auto_id=True) >>> print(f.as_table()) <tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" required></td></tr> <tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" required></td></tr> <tr><th><label for="sender">Sender:</label></th><td><input type="email" name="sender" id="sender" required></td></tr> <tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself"></td></tr> >>> print(f.as_ul()) <li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" required></li> <li><label for="message">Message:</label> <input type="text" name="message" id="message" required></li> <li><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" required></li> <li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself"></li> >>> print(f.as_p()) <p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" required></p> <p><label for="message">Message:</label> <input type="text" name="message" id="message" required></p> <p><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" required></p> <p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself"></p>
Если auto_id установлено в строку, содержащую символ формата '%s', вывод формы будет содержать теги <label>, и будут сгенерированы атрибуты id на основе строки формата. Например, для строки формата 'field_%s', поле с именем subject получит значение id 'field_subject'. Продолжим наш пример:
>>> f = ContactForm(auto_id='id_for_%s') >>> print(f.as_table()) <tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" required></td></tr> <tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" required></td></tr> <tr><th><label for="id_for_sender">Sender:</label></th><td><input type="email" name="sender" id="id_for_sender" required></td></tr> <tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></td></tr> >>> print(f.as_ul()) <li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li> <li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" required></li> <li><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" required></li> <li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li> >>> print(f.as_p()) <p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></p> <p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" required></p> <p><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" required></p> <p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></p>
Если auto_id установлено в любое другое истинное значение — например, в строку, которая не содержит %s — библиотека будет действовать так, как если бы auto_id было равно True.
По умолчанию auto_id установлено в строку 'id_%s'.
-
Form.label_suffix
Переводимая строка (по умолчанию двоеточие (:) на английском языке), которая будет добавляться после имени любой метки при рендеринге формы.
Можно настроить этот символ или полностью его опустить, используя параметр label_suffix:
>>> f = ContactForm(auto_id='id_for_%s', label_suffix='') >>> print(f.as_ul()) <li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li> <li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" required></li> <li><label for="id_for_sender">Sender</label> <input type="email" name="sender" id="id_for_sender" required></li> <li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li> >>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->') >>> print(f.as_ul()) <li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li> <li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" required></li> <li><label for="id_for_sender">Sender -></label> <input type="email" name="sender" id="id_for_sender" required></li> <li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li>
Обратите внимание, что суффикс метки добавляется только в том случае, если последний символ метки не является знаком препинания (на английском языке это ., !, ? или :).
Поля могут также определять собственный label_suffix. Это значение будет иметь приоритет над Form.label_suffix. Суффикс также может быть переопределён во время выполнения с помощью параметра label_suffix метода label_tag().
-
Form.use_required_attribute
При установке в True (значение по умолчанию), обязательные поля формы будут иметь HTML-атрибут required.
Наборы форм создают формы с use_required_attribute=False для предотвращения некорректной проверки браузером при добавлении и удалении форм из набора форм.
Настройка рендеринга виджетов формы
-
Form.default_renderer
Указывает рендерер, который нужно использовать для формы. По умолчанию None, что означает использование рендерера по умолчанию, указанного в настройке FORM_RENDERER.
Вы можете установить это как атрибут класса при объявлении формы или использовать аргумент renderer к Form.__init__(). Например:
from django import forms
class MyForm(forms.Form):
default_renderer = MyRenderer()
или:
form = MyForm(renderer=MyRenderer())
Замечания о порядке полей
В as_p(), as_ul() и as_table() сокращениях поля отображаются в том порядке, в котором вы их определяете в классе формы. Например, в примере ContactForm поля определены в порядке subject, message, sender, cc_myself. Чтобы изменить порядок вывода HTML, просто измените порядок, в котором эти поля перечислены в классе.
Существуют и другие способы настройки порядка:
-
Form.field_order
По умолчанию Form.field_order=None, что сохраняет порядок, в котором вы определяете поля в классе формы. Если field_order — список имён полей, поля упорядочиваются так, как указано в списке, а оставшиеся поля добавляются в соответствии с порядком по умолчанию. Неизвестные имена полей в списке игнорируются. Это позволяет отключить поле в подклассе, установив его в значение None без необходимости переопределения порядка.
Вы также можете использовать аргумент Form.field_order для Form, чтобы переопределить порядок полей. Если Form определяет field_order и вы включаете field_order при создании экземпляра Form, то последнее field_order будет иметь приоритет.
-
Form.order_fields(field_order)
Вы можете переупорядочить поля в любое время, используя order_fields() со списком имён полей, как в field_order.
Как отображаются ошибки
Если вы отображаете связанный объект Form, рендеринг автоматически выполнит валидацию формы, если она ещё не была выполнена, и вывод HTML будет включать ошибки валидации как <ul class="errorlist"> рядом с полем. Точное расположение сообщений об ошибках зависит от используемого метода вывода:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid email address',
... 'cc_myself': True}
>>> f = ContactForm(data, auto_id=False)
>>> print(f.as_table())
<tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" required></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" value="Hi there" required></td></tr>
<tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid email address.</li></ul><input type="email" name="sender" value="invalid email address" required></td></tr>
<tr><th>Cc myself:</th><td><input checked type="checkbox" name="cc_myself"></td></tr>
>>> print(f.as_ul())
<li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <input type="text" name="message" value="Hi there" required></li>
<li><ul class="errorlist"><li>Enter a valid email address.</li></ul>Sender: <input type="email" name="sender" value="invalid email address" required></li>
<li>Cc myself: <input checked type="checkbox" name="cc_myself"></li>
>>> print(f.as_p())
<p><ul class="errorlist"><li>This field is required.</li></ul></p>
<p>Subject: <input type="text" name="subject" maxlength="100" required></p>
<p>Message: <input type="text" name="message" value="Hi there" required></p>
<p><ul class="errorlist"><li>Enter a valid email address.</li></ul></p>
<p>Sender: <input type="email" name="sender" value="invalid email address" required></p>
<p>Cc myself: <input checked type="checkbox" name="cc_myself"></p>
Настройка формата списка ошибок
По умолчанию формы используют django.forms.utils.ErrorList для форматирования ошибок валидации. Если вы хотите использовать другой класс для отображения ошибок, вы можете передать его во время создания:
>>> from django.forms.utils import ErrorList >>> class DivErrorList(ErrorList): ... def __str__(self): ... return self.as_divs() ... def as_divs(self): ... if not self: return '' ... return '<div class="errorlist">%s</div>' % ''.join(['<div class="error">%s</div>' % e for e in self]) >>> f = ContactForm(data, auto_id=False, error_class=DivErrorList) >>> f.as_p() <div class="errorlist"><div class="error">This field is required.</div></div> <p>Subject: <input type="text" name="subject" maxlength="100" required></p> <p>Message: <input type="text" name="message" value="Hi there" required></p> <div class="errorlist"><div class="error">Enter a valid email address.</div></div> <p>Sender: <input type="email" name="sender" value="invalid email address" required></p> <p>Cc myself: <input checked type="checkbox" name="cc_myself"></p>
Более подробный вывод
Методы as_p(), as_ul() и as_table() являются всего лишь сокращениями — это не единственный способ отображения объекта формы.
-
class BoundField[source] -
Используется для отображения HTML или доступа к атрибутам для отдельного поля экземпляра
Form.Метод
__str__()этого объекта отображает HTML для этого поля.
Для получения отдельного BoundField, используйте синтаксис поиска по словарю в вашей форме, используя имя поля в качестве ключа:
>>> form = ContactForm() >>> print(form['subject']) <input id="id_subject" type="text" name="subject" maxlength="100" required>
Для получения всех BoundField объектов переберите форму:
>>> form = ContactForm() >>> for boundfield in form: print(boundfield) <input id="id_subject" type="text" name="subject" maxlength="100" required> <input type="text" name="message" id="id_message" required> <input type="email" name="sender" id="id_sender" required> <input type="checkbox" name="cc_myself" id="id_cc_myself">
Вывод, специфичный для поля, учитывает настройку объекта формы auto_id:
>>> f = ContactForm(auto_id=False) >>> print(f['message']) <input type="text" name="message" required> >>> f = ContactForm(auto_id='id_%s') >>> print(f['message']) <input type="text" name="message" id="id_message" required>
Атрибуты BoundField
-
BoundField.auto_id -
Атрибут HTML ID для этого
BoundField. Возвращает пустую строку, еслиForm.auto_idравноFalse.
-
BoundField.data -
Это свойство возвращает данные для этого
BoundField, извлеченные методом виджетаvalue_from_datadict(), илиNoneв случае отсутствия значения:>>> unbound_form = ContactForm() >>> print(unbound_form['subject'].data) None >>> bound_form = ContactForm(data={'subject': 'My Subject'}) >>> print(bound_form['subject'].data) My Subject
-
BoundField.errors -
Объект-список, отображаемый как HTML-элемент
<ul class="errorlist">при печати:>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''} >>> f = ContactForm(data, auto_id=False) >>> print(f['message']) <input type="text" name="message" required> >>> f['message'].errors ['This field is required.'] >>> print(f['message'].errors) <ul class="errorlist"><li>This field is required.</li></ul> >>> f['subject'].errors [] >>> print(f['subject'].errors) >>> str(f['subject'].errors) ''
-
BoundField.field -
Экземпляр формы
Fieldиз класса формы, который оборачивает этотBoundField.
-
BoundField.form -
Экземпляр
Form, к которому привязан этотBoundField.
-
BoundField.help_text -
Текст справки поля.
-
BoundField.html_name -
Имя, которое будет использовано в атрибуте HTML
nameвиджета. Оно учитывает значениеprefix.
-
BoundField.id_for_label -
Используйте этот метод для отображения ID поля. Например, если вы вручную формируете
<label>в вашем шаблоне (хотяlabel_tag()сделает это за вас):<label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}По умолчанию, это будет имя поля, префиксное значением
id_(“id_my_field” в приведённом примере). Вы можете изменить ID, установивattrsна виджете поля. Например, объявив поле так:my_field = forms.CharField(widget=forms.TextInput(attrs={'id': 'myFIELD'}))и используя указанный выше шаблон, будет отображено что-то вроде:
<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" required>
-
Возвращает
True, если виджет этого поляBoundFieldскрыт.
-
BoundField.label -
Метка поля.
-
BoundField.name -
Имя этого поля в форме:
>>> f = ContactForm() >>> print(f['subject'].name) subject >>> print(f['message'].name) message
Методы BoundField
-
Возвращает строку HTML для представления этого поля как
<input type="hidden">.Значения
**kwargsпередаются вas_widget().Этот метод в основном используется внутри. Вы должны использовать виджет.
-
BoundField.as_widget(widget=None, attrs=None, only_initial=False)[source] -
Отображает поле, используя переданный виджет и добавляя атрибуты HTML, переданные как
attrs. Если виджет не указан, используется стандартный виджет поля.only_initialиспользуется внутренними механизмами Django и не должен устанавливаться явно.
-
BoundField.css_classes()[source] -
При использовании сокращений Django для отображения, CSS классы используются для обозначения обязательных полей формы или полей, содержащих ошибки. Если вы вручную отображаете форму, вы можете получить доступ к этим классам CSS с помощью метода
css_classes.>>> f = ContactForm(data={'message': ''}) >>> f['message'].css_classes() 'required'Если вам нужно добавить дополнительные классы помимо классов ошибок и обязательных, вы можете указать их в качестве аргумента:
>>> f = ContactForm(data={'message': ''}) >>> f['message'].css_classes('foo bar') 'foo bar required'
-
BoundField.label_tag(contents=None, attrs=None, label_suffix=None)[source] -
Для отдельного отображения тега метки поля формы можно вызвать его метод
label_tag():>>> f = ContactForm(data={'message': ''}) >>> print(f['message'].label_tag()) <label for="id_message">Message:</label>Вы можете предоставить параметр
contents, который заменит автоматически сгенерированный тег метки. Словарьattrsможет содержать дополнительные атрибуты для тега<label>.В генерируемом HTML используется суффикс метки формы
label_suffix(двоеточие по умолчанию) или, если установлено, суффикс метки текущего поляlabel_suffix. Параметрlabel_suffixпозволяет переопределить ранее установленный суффикс. Например, вы можете использовать пустую строку, чтобы скрыть метку для выбранных полей. Если вам нужно сделать это в шаблоне, вы можете написать пользовательский фильтр для передачи параметров вlabel_tag.
-
BoundField.value()[source] -
Используйте этот метод для отображения исходного значения поля так, как оно было бы отображено
Widget:>>> initial = {'subject': 'welcome'} >>> unbound_form = ContactForm(initial=initial) >>> bound_form = ContactForm(data={'subject': 'hi'}, initial=initial) >>> print(unbound_form['subject'].value()) welcome >>> print(bound_form['subject'].value()) hi
Настройка BoundField
Если вам нужно получить дополнительную информацию о поле формы в шаблоне, и наследование от Field недостаточно, рассмотрите возможность настройки BoundField.
Пользовательское поле формы может переопределить get_bound_field():
-
Field.get_bound_field(form, field_name)[source] -
Принимает экземпляр
Formи имя поля. Возвращаемое значение будет использоваться при доступе к полю в шаблоне. Скорее всего, это будет экземпляр подклассаBoundField.
Если у вас есть, например, GPSCoordinatesField, и вы хотите получить доступ к дополнительной информации о координатах в шаблоне, это можно реализовать следующим образом:
class GPSCoordinatesBoundField(BoundField):
@property
def country(self):
"""
Return the country the coordinates lie in or None if it can't be
determined.
"""
value = self.value()
if value:
return get_country_from_coordinates(value)
else:
return None
class GPSCoordinatesField(Field):
def get_bound_field(self, form, field_name):
return GPSCoordinatesBoundField(form, self, field_name)
Теперь в шаблоне вы можете получить доступ к стране с помощью {{ form.coordinates.country }}.
Связывание загруженных файлов с формой
Работа с формами, содержащими поля FileField и ImageField немного сложнее, чем с обычной формой.
Во-первых, для загрузки файлов вам нужно убедиться, что ваш элемент <form> правильно определяет enctype как "multipart/form-data":
<form enctype="multipart/form-data" method="post" action="/foo/">
Во-вторых, при использовании формы вам необходимо связать данные файла. Данные файла обрабатываются отдельно от обычных данных формы, поэтому, когда ваша форма содержит FileField и ImageField, при связывании формы вам необходимо указать второй аргумент. Таким образом, если мы расширим нашу ContactForm, чтобы добавить поле ImageField с именем mugshot, нам нужно связать данные файла, содержащие изображение портрета:
# Bound form with an image field
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)}
>>> f = ContactFormWithMugshot(data, file_data)
На практике, вы обычно указываете request.FILES в качестве источника данных файла (точно так же, как вы используете request.POST в качестве источника данных формы):
# Bound form with an image field, data from the request >>> f = ContactFormWithMugshot(request.POST, request.FILES)
Создание несвязанной формы такая же, как всегда – просто опустите данные формы и данные файла:
# Unbound form with an image field >>> f = ContactFormWithMugshot()
Проверка на multipart формы
-
Form.is_multipart()
Если вы пишете многократно используемые представления или шаблоны, вы можете не знать заранее, является ли ваша форма multipart-формой или нет. Метод is_multipart() сообщает вам, требуется ли для отправки формы multipart кодирование:
>>> f = ContactFormWithMugshot() >>> f.is_multipart() True
Вот пример, как вы можете использовать это в шаблоне:
{% if form.is_multipart %}
<form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
<form method="post" action="/foo/">
{% endif %}
{{ form }}
</form>
Наследование от форм
Если у вас есть несколько классов Form с общими полями, вы можете использовать наследование, чтобы избежать дублирования.
При наследовании от пользовательского класса Form, полученный подкласс будет включать все поля родительского класса (классов), за которыми следуют поля, определённые в подклассе.
В этом примере ContactFormWithPriority содержит все поля из ContactForm, плюс дополнительное поле priority. Поля ContactForm упорядочены первыми:
>>> class ContactFormWithPriority(ContactForm): ... priority = forms.CharField() >>> f = ContactFormWithPriority(auto_id=False) >>> print(f.as_ul()) <li>Subject: <input type="text" name="subject" maxlength="100" required></li> <li>Message: <input type="text" name="message" required></li> <li>Sender: <input type="email" name="sender" required></li> <li>Cc myself: <input type="checkbox" name="cc_myself"></li> <li>Priority: <input type="text" name="priority" required></li>
Можно наследовать от нескольких форм, рассматривая формы как миксины. В этом примере BeatleForm наследуется от PersonForm и InstrumentForm (в указанном порядке), и его список полей включает поля из родительских классов:
>>> from django import forms >>> class PersonForm(forms.Form): ... first_name = forms.CharField() ... last_name = forms.CharField() >>> class InstrumentForm(forms.Form): ... instrument = forms.CharField() >>> class BeatleForm(InstrumentForm, PersonForm): ... haircut_type = forms.CharField() >>> b = BeatleForm(auto_id=False) >>> print(b.as_ul()) <li>First name: <input type="text" name="first_name" required></li> <li>Last name: <input type="text" name="last_name" required></li> <li>Instrument: <input type="text" name="instrument" required></li> <li>Haircut type: <input type="text" name="haircut_type" required></li>
Можно декларативно удалить поле Field, унаследованное от родительского класса, установив имя поля в None в подклассе. Например:
>>> from django import forms >>> class ParentForm(forms.Form): ... name = forms.CharField() ... age = forms.IntegerField() >>> class ChildForm(ParentForm): ... name = None >>> list(ChildForm().fields) ['age']
Префиксы для форм
-
Form.prefix
Вы можете поместить несколько форм Django внутри одного тега <form>. Чтобы дать каждой форме своё пространство имён, используйте ключевое слово prefix.
>>> mother = PersonForm(prefix="mother") >>> father = PersonForm(prefix="father") >>> print(mother.as_ul()) <li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" required></li> <li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" required></li> >>> print(father.as_ul()) <li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" required></li> <li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" required></li>
Префикс также может быть задан в классе формы:
>>> class PersonForm(forms.Form): ... ... ... prefix = 'person'
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.1/ref/forms/api/