Spec-Zone.ru › Django 1.11

API форм

О документе

В этом документе подробно описан API форм Django. Сначала следует прочитать введение в работу с формами.

Связанные и несвязанные формы

Экземпляр Form может быть либо связан с набором данных, либо несвязан.

  • Если он связан с набором данных, он может валидировать эти данные и отобразить форму в HTML с отображенными в HTML данными.
  • Если он несвязан, он не может выполнять валидацию (потому что нет данных для валидации!), но он все равно может отобразить пустую форму в HTML.
class Form [исходный код]

Чтобы создать экземпляр несвязанной 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.']}

В этом словаре ключи — это имена полей, а значения — списки Unicode-строк, представляющих сообщения об ошибках. Сообщения об ошибках хранятся в списках, потому что у поля может быть несколько сообщений об ошибках.

Вы можете получить доступ к errors, не вызывая is_valid() сначала. Данные формы будут валидироваться в первый раз, когда вы вызовете is_valid() или обратитесь к errors.

Процедуры валидации будут вызываться только один раз, независимо от того, сколько раз вы обращаетесь к errors или вызываете is_valid(). Это означает, что если валидация имеет побочные эффекты, эти побочные эффекты будут срабатывать только один раз.

Form.errors.as_data()

Возвращает словарь, отображающий поля к их исходным экземплярам ValidationError.

>>> 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.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, которые не связаны с конкретным полем. Это включает ValidationErrors, которые генерируются в 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)
Новое в Django 1.11.

Используйте 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>
Изменено в Django 1.11:

Атрибут checked был изменён на использование синтаксиса булевых значений HTML5 вместо checked="checked".

Этот вывод по умолчанию — HTML-таблица из двух столбцов, с <tr> для каждого поля. Обратите внимание на следующее:

  • Для гибкости вывод не включает теги <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> является стилем вывода по умолчанию, когда вы print форму, доступны и другие стили вывода. Каждый стиль доступен как метод объекта формы, и каждый метод рендеринга возвращает объект Юникод.

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-таблицы. Это полностью идентично 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-атрибутов и тегов <label> элементов формы

Form.auto_id

По умолчанию методы рендеринга формы включают:

  • HTML-атрибуты на элементах формы.
  • Соответствующие теги <label> вокруг меток. Тег <label> в HTML определяет, какой текст метки связан с каким элементом формы. Это небольшое улучшение делает формы более удобными и доступными для вспомогательных устройств. Всегда рекомендуется использовать теги <label>.

Значения атрибута id генерируются путем добавления префикса id_ к именам полей формы. Однако это поведение настраивается, если вы хотите изменить соглашение id или полностью удалить атрибуты HTML и теги <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 получит значение '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
Новое в Django 1.10.

Если установлено в True (значение по умолчанию), для обязательных полей формы будет установлен HTML-атрибут required.

Formsets создают формы с use_required_attribute=False для предотвращения неправильной проверки браузера при добавлении и удалении форм из набора форм.

Настройка отображения виджетов формы

Form.default_renderer
Новое в Django 1.11.

Указывает, какой рендерер использовать для формы. По умолчанию 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 для форматирования ошибок валидации. Если вы хотите использовать другой класс для отображения ошибок, вы можете передать его во время создания (замените __str__ на __unicode__ в Python 2):

>>> from django.forms.utils import ErrorList
>>> class DivErrorList(ErrorList):
...     def __str__(self):              # __unicode__ on Python 2
...         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__() (__unicode__ в Python 2) этого объекта отображает 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 для этого 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

Описание поля 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 />
BoundField.is_hidden

Возвращает True если виджет этого BoundField скрыт.

BoundField.label

Текст метки label поля. Это используется в label_tag().

BoundField.name

Имя этого поля в форме:

>>> f = ContactForm()
>>> print(f['subject'].name)
subject
>>> print(f['message'].name)
message

Методы BoundField

BoundField.as_hidden(attrs=None, **kwargs) [source]

Возвращает строку 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, нам нужно привязать данные файла, содержащие изображение 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>. Чтобы каждому 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/1.11/ref/forms/api/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API