Spec-Zone.ru › Django 5.0

API форм

О документе

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

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

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

  • Если он связан с набором данных, он может валидировать эти данные и отобразить форму в 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, которые не связаны с конкретным полем. Сюда входят ValidationErrorы, которые были вызваны в 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)
<div>Name:<input type="text" name="name" value="instance" required></div>
<div>Url:<input type="url" name="url" required></div>
<div>Comment:<input type="text" name="comment" required></div>
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)
<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>

Если форма связана с данными, 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)
<div><label for="id_subject">Subject:</label><input type="text" name="subject" value="hello" maxlength="100" required id="id_subject"></div>
<div><label for="id_message">Message:</label><input type="text" name="message" value="Hi there" required id="id_message"></div>
<div><label for="id_sender">Sender:</label><input type="email" name="sender" value="foo@example.com" required id="id_sender"></div>
<div><label for="id_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_cc_myself" checked></div>

Этот вывод по умолчанию обертывает каждое поле в <div>. Обратите внимание на следующее:

  • Для гибкости вывод не включает теги <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'.

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

Вывод по умолчанию

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

Имя шаблона

Form.template_name

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

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

Метод render

Form.render(template_name=None, context=None, renderer=None)

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

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

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

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

Form.get_context()

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

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

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

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

Form.template_name_label

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

Стили вывода

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

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

Примечание

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

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

as_div

Form.template_name_div

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

Form.as_div()

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_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>:

>>> 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)
<div class="required"><label for="id_subject" class="required">Subject:</label> ...
<div class="required"><label for="id_message" class="required">Message:</label> ...
<div class="required"><label for="id_sender" class="required">Sender:</label> ...
<div><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 для управления поведением меток и подписей. Этот аргумент должен быть True, False или строкой.

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

>>> f = ContactForm(auto_id=False)
>>> print(f)
<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)
<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)
<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)
<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)
<div><label for="id_for_subject">Subject -&gt;</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 (по умолчанию), обязательные поля формы будут иметь атрибут 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)
<div>Subject:
  <ul class="errorlist"><li>This field is required.</li></ul>
  <input type="text" name="subject" maxlength="100" required aria-invalid="true">
</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 aria-invalid="true">
</div>
<div>Cc myself:
  <input type="checkbox" name="cc_myself" checked>
</div>

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

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

Более детализированный вывод

Методы 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 aria-invalid="true">
>>> 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)
''

При рендеринге поля с ошибками, aria-invalid="true" будет установлено для виджета поля, чтобы сообщить пользователям-скринридерам о наличии ошибки.

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

aria-invalid="true" было добавлено, когда у поля есть ошибки.

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.template_name
Новое в Django 5.0.

Имя шаблона, используемого для отображения с помощью BoundField.as_field_group().

Свойство, возвращающее значение template_name, если оно установлено, в противном случае field_template_name.

BoundField.use_fieldset

Возвращает значение атрибута 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_field_group()
Новое в Django 5.0.

Отображает поле с помощью BoundField.render() с заданными значениями по умолчанию, что отображает BoundField, включая его метку, подсказку и ошибки, используя шаблон template_name, если он задан, в противном случае field_template_name

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.get_context()
Новое в Django 5.0.

Возвращает контекст шаблона для отображения поля. Доступный контекст – field — это экземпляр связанного поля.

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

BoundField.legend_tag(contents=None, attrs=None, label_suffix=None)

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

BoundField.render(template_name=None, context=None, renderer=None)
Новое в Django 5.0.

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

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

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

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)
<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)
<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)
<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)
<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/5.0/ref/forms/api/

Spec-Zone.ru

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