Spec-Zone.ru › Django 4.2

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 в представление формы, где клиент интерпретирует ответ и вставляет ошибки на страницу, вам нужно убедиться, что результаты экранированы на стороне клиента, чтобы избежать возможности атаки XSS. Вы можете сделать это в JavaScript с помощью element.textContent = errorText или с помощью jQuery $(el).text(errorText) (а не его функции .html()).

Если по какой-то причине вы не хотите использовать экранирование на стороне клиента, вы также можете установить escape_html=True, и сообщения об ошибках будут экранированы, так что вы можете использовать их непосредственно в HTML.

Form.errors.get_json_data(escape_html=False)

Возвращает ошибки в виде словаря, подходящего для сериализации в JSON. Form.errors.as_json() возвращает сериализованный JSON, а это возвращает данные об ошибках до сериализации.

Параметр escape_html ведет себя так же, как описано в Form.errors.as_json().

Form.add_error(field, error)

Этот метод позволяет добавлять ошибки к определённым полям изнутри метода Form.clean(), или извне формы; например, из представления.

Аргумент field — имя поля, к которому должны быть добавлены ошибки. Если его значение None, ошибка будет обработана как ошибка вне поля, как возвращается Form.non_field_errors().

Аргумент error может быть строкой или, что предпочтительнее, экземпляром ValidationError. См. Возбуждение ValidationError для рекомендаций по определению ошибок формы.

Обратите внимание, что Form.add_error() автоматически удаляет соответствующее поле из cleaned_data.

Form.has_error(field, code=None)

Этот метод возвращает логическое значение, указывающее, содержит ли поле ошибку с указанной ошибкой code. Если code равно None, он вернёт True, если поле содержит какие-либо ошибки.

Для проверки ошибок вне поля используйте NON_FIELD_ERRORS в качестве параметра field.

Form.non_field_errors()

Этот метод возвращает список ошибок из Form.errors, которые не связаны с конкретным полем. Это включает ошибки, которые генерируются в Form.clean() и ошибки, добавленные с помощью Form.add_error(None, "...").

Поведение несвязанных форм

Проверка формы без данных бессмысленна, но для справки, вот что происходит с несвязанными формами:

>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}

Начальные значения формы

Form.initial

Используйте initial, чтобы объявить начальное значение полей формы во время выполнения. Например, вы можете заполнить поле username именем пользователя текущей сессии.

Для этого используйте аргумент initial формы Form. Этот аргумент, если задан, должен быть словарем, сопоставляющим имена полей с начальными значениями. Включайте только те поля, для которых вы указываете начальное значение; не нужно включать каждое поле формы. Например:

>>> f = ContactForm(initial={"subject": "Hi there!"})

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

Если Field определяет initial и вы включаете initial при создании объекта Form, то последнее initial будет иметь приоритет. В данном примере, initial указано как на уровне поля, так и на уровне экземпляра формы, и приоритет имеет последнее:

>>> from django import forms
>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial="class")
...     url = forms.URLField()
...     comment = forms.CharField()
...
>>> f = CommentForm(initial={"name": "instance"}, auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="instance" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" required></td></tr>
Form.get_initial_for_field(field, field_name)

Возвращает начальные данные для поля формы. Получает данные из 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>

Вы можете изменить поле и BoundField экземпляра Form, чтобы изменить способ его отображения в форме.

>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
>>> f["subject"].label = "Topic"
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Topic:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'

Будьте осторожны, не изменяйте атрибут base_fields, так как это изменение повлияет на все последующие экземпляры ContactForm в том же процессе Python.

>>> f.base_fields["subject"].label_suffix = "?"
>>> another_f = CommentForm(auto_id=False)
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject?</label><input type="text" name="subject" maxlength="100" required id="id_subject">'

Доступ к "очищенным" данным

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 формы использует следующие методы и атрибуты.

template_name

Form.template_name

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

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

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

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

render()

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, вы можете настроить шаблон, используемый только для одного вызова.

get_context()

Form.get_context()

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

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

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

template_name_label

Form.template_name_label

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

Стили вывода

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

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

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

as_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> для группировки связанных входов и его легче использовать пользователям с программами экранного чтения.

as_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>

as_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>

as_table()

Form.template_name_table

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

Form.as_table()

as_table() отображает форму в виде HTML <table>.

Стиль необходимых или ошибочных строк формы

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_div())
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
<div>Sender:<input type="email" name="sender" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself"></div>

Если auto_id установлено в значение True, вывод формы будет включать теги <label>, и будет использовать имя поля в качестве id для каждого поля формы:

>>> f = ContactForm(auto_id=True)
>>> print(f.as_div())
<div><label for="subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="subject"></div>
<div><label for="message">Message:</label><textarea name="message" cols="40" rows="10" required id="message"></textarea></div>
<div><label for="sender">Sender:</label><input type="email" name="sender" required id="sender"></div>
<div><label for="cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="cc_myself"></div>

Если auto_id установлено в строку, содержащую символ формата '%s', вывод формы будет включать теги <label>, и будет генерировать атрибуты id на основе строки формата. Например, для строки формата 'field_%s', поле с именем subject получит значение id 'field_subject'. Продолжая наш пример:

>>> f = ContactForm(auto_id="id_for_%s")
>>> print(f.as_div())
<div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message:</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender:</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>

Если 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_div())
<div><label for="id_for_subject">Subject</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>
>>> f = ContactForm(auto_id="id_for_%s", label_suffix=" ->")
>>> print(f.as_div())
<div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message -&gt;</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender -&gt;</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself -&gt;</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>

Обратите внимание, что суффикс метки добавляется только в том случае, если последний символ метки не является знаком препинания (на английском языке это ., !, ? или :).

Поля также могут определять собственное label_suffix. Это будет иметь приоритет над Form.label_suffix. Суффикс также может быть переопределён во время выполнения с помощью параметра label_suffix для label_tag()/ legend_tag().

Form.use_required_attribute

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

Наборы форм инициализируют формы с 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_div())
<div>Subject:<ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required>Hi there</textarea></div>
<div>Sender:<ul class="errorlist"><li>Enter a valid email address.</li></ul><input type="email" name="sender" value="invalid email address" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself" checked></div>
>>> 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><textarea name="message" cols="40" rows="10" required></textarea></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: <textarea name="message" cols="40" rows="10" required></textarea></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: <textarea name="message" cols="40" rows="10" required></textarea></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

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

template_name

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

template_name_text

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

template_name_ul

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

get_context()

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

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

  • errors : Список ошибок.
  • error_class : Строка классов CSS.
render(template_name=None, context=None, renderer=None)

Метод 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 или, в более общем случае, переопределяя шаблон по умолчанию, см. также Переопределение встроенных шаблонов формы.

Устарело начиная с версии 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.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", b"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_div())
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
<div>Sender:<input type="email" name="sender" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself"></div>
<div>Priority:<input type="text" name="priority" required></div>

Можно наследовать от нескольких форм, используя формы как миксины. В этом примере 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_div())
<div>First name:<input type="text" name="first_name" required></div>
<div>Last name:<input type="text" name="last_name" required></div>
<div>Instrument:<input type="text" name="instrument" required></div>
<div>Haircut type:<input type="text" name="haircut_type" required></div>

Можно декларативно удалить поле 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_div())
<div><label for="id_mother-first_name">First name:</label><input type="text" name="mother-first_name" required id="id_mother-first_name"></div>
<div><label for="id_mother-last_name">Last name:</label><input type="text" name="mother-last_name" required id="id_mother-last_name"></div>
>>> print(father.as_div())
<div><label for="id_father-first_name">First name:</label><input type="text" name="father-first_name" required id="id_father-first_name"></div>
<div><label for="id_father-last_name">Last name:</label><input type="text" name="father-last_name" required id="id_father-last_name"></div>

Префикс также можно указать в классе формы:

>>> class PersonForm(forms.Form):
...     ...
...     prefix = "person"
...

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.2/ref/forms/api/

Spec-Zone.ru

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