Spec-Zone.ru › Django 4.1

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.']}

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

Вы можете получить доступ к 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 это можно сделать с помощью element.textContent = errorText или с помощью jQuery’s $(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)

Возвращает начальные данные для поля формы. Оно извлекает данные из Form.initial, если оно присутствует, иначе пытается получить данные из Field.initial. Значения-вызовы вычисляются.

Рекомендуется использовать BoundField.initial вместо get_initial_for_field(), потому что BoundField.initial имеет более простой интерфейс. Кроме того, в отличие от get_initial_for_field(), BoundField.initial кеширует свои значения. Это полезно особенно при работе с вызовами, значения возвращаемых которых могут меняться (например, datetime.now или uuid.uuid4):

>>> import uuid
>>> class UUIDCommentForm(CommentForm):
...     identifier = forms.UUIDField(initial=uuid.uuid4)
>>> f = UUIDCommentForm()
>>> f.get_initial_for_field(f.fields['identifier'], 'identifier')
UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334')
>>> f.get_initial_for_field(f.fields['identifier'], 'identifier')
UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0')
>>> # Using BoundField.initial, for comparison
>>> f['identifier'].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
>>> f['identifier'].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')

Проверка изменений данных формы

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))
>>> f.changed_data
['subject', 'message']

Доступ к полям из формы

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-таблица с <tr> для каждого поля. Обратите внимание на следующее:

  • Для гибкости вывод не включает теги <table> и </table>, а также теги <form> и </form> или тег <input type="submit">. Вам нужно сделать это самостоятельно.
  • Каждый тип поля имеет стандартное HTML-представление. CharField представлен тегом <input type="text">, а EmailField — тегом <input type="email">. BooleanField(null=False) представлен тегом <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 форму, доступны другие стили вывода. Каждый стиль доступен в виде метода объекта формы, и каждый метод отрисовки возвращает строку.

Отрисовка по умолчанию

Отрисовка по умолчанию при print формы использует следующие методы и атрибуты.

Имя шаблона

Новое в Django 4.0.
Form.template_name

Имя шаблона, используемого для отрисовки формы, если она приводится к строке, например, через print(form) или в шаблоне через {{ form }}.

По умолчанию свойство, возвращающее значение form_template_name рендерера. Вы можете установить его в виде имени шаблона строки, чтобы переопределить это для конкретного класса формы.

Изменено в Django 4.1:

В более старых версиях template_name по умолчанию имело строковое значение 'django/forms/default.html'.

Отрисовка

Новое в Django 4.0.
Form.render(template_name=None, context=None, renderer=None)

Метод render вызывается при __str__, а также методами Form.as_table(), Form.as_p() и Form.as_ul(). Все аргументы необязательны и по умолчанию:

  • template_name: Form.template_name
  • context: Значение, возвращаемое Form.get_context()
  • renderer: Значение, возвращаемое Form.default_renderer

Передав template_name, вы можете настроить шаблон, используемый только для одного вызова.

Получить контекст

Новое в Django 4.0.
Form.get_context()

Возвращает контекст шаблона для отрисовки формы.

Доступный контекст:

  • form: Связанная форма.
  • fields: Все связанные поля, кроме скрытых.
  • hidden_fields: Все связанные скрытые поля.
  • errors: Все ошибки формы, не связанные с полями или скрытыми полями.

Имя шаблона метки

Новое в Django 4.0.
Form.template_name_label

Шаблон, используемый для отрисовки <label> поля, используемого при вызове BoundField.label_tag()/legend_tag(). Может быть изменён для каждой формы путём переопределения этого атрибута или, более обще, путём переопределения стандартного шаблона, см. также Переопределение встроенных шаблонов форм.

Стили вывода

Помимо прямой отрисовки формы, например, в шаблоне с {{ form }}, следующие вспомогательные функции служат прокси для Form.render(), передавая определённое значение template_name.

Эти вспомогательные функции наиболее полезны в шаблоне, когда вам нужно переопределить рендерер формы или значение, предоставленное формой, но вы не можете передать дополнительный параметр в render(). Например, вы можете отобразить форму как неупорядоченный список с помощью {{ form.as_ul }}.

Каждая вспомогательная функция сопоставляет метод формы с атрибутом, задающим соответствующее имя шаблона.

Вывод в div

Form.template_name_div
Новое в Django 4.1.

Шаблон, используемый в as_div(). По умолчанию: 'django/forms/div.html'.

Form.as_div()
Новое в Django 4.1.

as_div() отображает форму в виде набора элементов <div>, где каждый <div> содержит одно поле, например:

>>> f = ContactForm()
>>> f.as_div()

… генерирует HTML, подобный:

<div>
<label for="id_subject">Subject:</label>
<input type="text" name="subject" maxlength="100" required id="id_subject">
</div>
<div>
<label for="id_message">Message:</label>
<input type="text" name="message" required id="id_message">
</div>
<div>
<label for="id_sender">Sender:</label>
<input type="email" name="sender" required id="id_sender">
</div>
<div>
<label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself">
</div>

Примечание

Из представленных в рамках фреймворка шаблонов и стилей вывода as_div() рекомендуется по сравнению с as_p(), as_table() и as_ul(), так как шаблон реализует <fieldset> и <legend> для группировки связанных входных данных и проще для пользователей с программами экранного доступа.

Вывод в p

Form.template_name_p

Шаблон, используемый в as_p(). По умолчанию: 'django/forms/p.html'.

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>

Вывод в ul

Form.template_name_ul

Шаблон, используемый в as_ul(). По умолчанию: 'django/forms/ul.html'.

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>

Вывод в таблицу

Form.template_name_table

Шаблон, используемый в as_table(). По умолчанию: 'django/forms/table.html'.

Form.as_table()

as_table() отображает форму в виде HTML <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'].legend_tag()
<legend class="required" for="id_subject">Subject:</legend>
>>> f['subject'].label_tag(attrs={'class': 'foo'})
<label for="id_subject" class="foo required">Subject:</label>
>>> f['subject'].legend_tag(attrs={'class': 'foo'})
<legend for="id_subject" class="foo required">Subject:</legend>

Настройка атрибутов HTML id и тегов <label> элементов формы

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()/ legend_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>

Настройка формата списка ошибок

class ErrorList(initlist=None, error_class=None, renderer=None)

По умолчанию формы используют django.forms.utils.ErrorList для форматирования ошибок валидации. ErrorList — это объект типа списка, где initlist — это список ошибок. Кроме того, у этого класса есть следующие атрибуты и методы.

error_class

Классы CSS, используемые при отрисовке списка ошибок. Любые указанные классы добавляются к стандартному классу errorlist.

renderer
Новая функция в Django 4.0.

Указывает рендерер для использования при отрисовке ErrorList. По умолчанию используется None, что означает использование стандартного рендерера, определённого в настройке FORM_RENDERER.

template_name
Новая функция в Django 4.0.

Имя шаблона, используемого при вызове __str__ или render(). По умолчанию это 'django/forms/errors/list/default.html', который является псевдонимом шаблона 'ul.html'.

template_name_text
Новая функция в Django 4.0.

Имя шаблона, используемого при вызове as_text(). По умолчанию это 'django/forms/errors/list/text.html'. Этот шаблон отображает ошибки в виде маркированного списка.

template_name_ul
Новая функция в Django 4.0.

Имя шаблона, используемого при вызове as_ul(). По умолчанию это 'django/forms/errors/list/ul.html'. Этот шаблон отображает ошибки в тегах <li> с обертывающим тегом <ul> с классами CSS, определёнными в error_class.

get_context()
Новая функция в Django 4.0.

Возвращает контекст для отображения ошибок в шаблоне.

Доступный контекст:

  • errors : Список ошибок.
  • error_class : Строка с классами CSS.
render(template_name=None, context=None, renderer=None)
Новая функция в Django 4.0.

Метод render вызывается __str__ , а также методом as_ul().

Все аргументы необязательны и будут иметь значения по умолчанию:

  • template_name: Значение, возвращаемое template_name
  • context: Значение, возвращаемое get_context()
  • renderer: Значение, возвращаемое renderer
as_text()

Отображает список ошибок с использованием шаблона, определённого в template_name_text.

as_ul()

Отображает список ошибок с использованием шаблона, определённого в template_name_ul.

Если вы хотите настроить отображение ошибок, можно переопределить атрибут template_name или, более универсально, переопределить шаблон по умолчанию, см. также Переопределение встроенных шаблонов формы.

Изменено в Django 4.0:

Отображение ErrorList перенесено в движок шаблонов.

Устаревшее начиная с версии 4.0: Возможность возвращения str при вызове метода __str__ устарела. Используйте движок шаблонов, который возвращает SafeString.

Более подробный вывод

Методы as_p(), as_ul(), и as_table() являются сокращениями — они не единственный способ отображения объекта формы.

class BoundField

Используется для отображения 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

Поле help_text.

BoundField.html_name

Имя, которое будет использоваться в атрибуте HTML name виджета. Оно учитывает prefix.

BoundField.id_for_label

Используйте это свойство для рендеринга ID этого поля. Например, если вы вручную создаёте <label> в своём шаблоне (несмотря на то, что label_tag()/legend_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.initial

Используйте BoundField.initial для получения начальных данных для поля формы. Оно извлекает данные из Form.initial, если оно присутствует, в противном случае пытается получить данные из Field.initial. Значения-выражения вычисляются. См. Начальные значения формы для получения дополнительных примеров.

BoundField.initial кеширует возвращаемое значение, что полезно, особенно при работе со вызовами, возвращаемые значения которых могут изменяться (например, datetime.now или uuid.uuid4):

>>> from datetime import datetime
>>> class DatedCommentForm(CommentForm):
...     created = forms.DateTimeField(initial=datetime.now)
>>> f = DatedCommentForm()
>>> f['created'].initial
datetime.datetime(2021, 7, 27, 9, 5, 54)
>>> f['created'].initial
datetime.datetime(2021, 7, 27, 9, 5, 54)

Рекомендуется использовать BoundField.initial вместо get_initial_for_field().

BoundField.is_hidden

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

BoundField.label

Метка label поля. Используется в label_tag()/legend_tag().

BoundField.name

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

>>> f = ContactForm()
>>> print(f['subject'].name)
subject
>>> print(f['message'].name)
message
BoundField.use_fieldset
Новое в Django 4.1.

Возвращает значение атрибута use_fieldset виджета этого BoundField.

BoundField.widget_type

Возвращает имя класса обернутого виджета поля в нижнем регистре, с удаленными любыми окончаниями input или widget. Это может быть использовано при построении форм, где макет зависит от типа виджета. Например:

{% for field in form %}
    {% if field.widget_type == 'checkbox' %}
        # render one way
    {% else %}
        # render another way
    {% endif %}
{% endfor %}

Методы BoundField

BoundField.as_hidden(attrs=None, **kwargs)

Возвращает строку HTML для представления этого поля как <input type="hidden">.

**kwargs передаются в as_widget().

Этот метод используется в основном внутри. Вы должны использовать виджет.

BoundField.as_widget(widget=None, attrs=None, only_initial=False)

Отображает поле, отрисовывая переданный виджет, добавляя любые атрибуты HTML, переданные как attrs. Если виджет не указан, используется стандартный виджет поля.

only_initial используется внутренними компонентами Django и не должен устанавливаться явно.

BoundField.css_classes(extra_classes=None)

При использовании сокращений рендеринга 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, tag=None)

Отображает тег метки для поля формы, используя шаблон, указанный в Form.template_name_label.

Доступный контекст:

  • field: Этот экземпляр BoundField.
  • contents: По умолчанию склеенная строка из BoundField.label и Form.label_suffix (или Field.label_suffix, если установлено). Это можно переопределить параметрами contents и label_suffix.
  • attrs: Словарь, содержащий for, Form.required_css_class и id. id генерируется виджетом поля attrs или BoundField.auto_id. Дополнительные атрибуты могут быть предоставлены с помощью аргумента attrs.
  • use_tag: Логическое значение, которое True если у метки есть id. Если False , то стандартный шаблон опускает tag.
  • tag: Необязательная строка для настройки тега, по умолчанию label.

Подсказка

В вашем шаблоне field - это экземпляр BoundField. Следовательно, field.field получает доступ к BoundField.field, представляющему поле, которое вы объявляете, например, forms.CharField.

Для отдельной отрисовки тега метки поля формы вы можете вызвать его метод label_tag():

>>> f = ContactForm(data={'message': ''})
>>> print(f['message'].label_tag())
<label for="id_message">Message:</label>

Если вам нужно настроить отображение, это можно сделать, переопределив атрибут Form.template_name_label, или, более обще, переопределив шаблон по умолчанию. См. также Переопределение встроенных шаблонов форм.

Изменено в Django 4.0:

Метка теперь отрисовывается с помощью движка шаблонов.

Изменено в Django 4.1:

Добавлен аргумент tag.

BoundField.legend_tag(contents=None, attrs=None, label_suffix=None)
Новое в Django 4.1.

Вызывает label_tag() с tag='legend' для отрисовки метки с тегами <legend>. Это полезно при отрисовке виджетов радио и множественных чекбоксов, где <legend> может быть более уместным, чем <label>.

BoundField.value()

Используйте этот метод для рендеринга исходного значения этого поля так, как оно было бы отображено 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)

Принимает экземпляр 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()

Проверка на многочисленные формы

Form.is_multipart()

Если вы пишете многократно используемые представления или шаблоны, вы можете не знать заранее, является ли ваша форма многочастной формой. Метод is_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/4.1/ref/forms/api/

Spec-Zone.ru

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