Spec-Zone.ru › Django 5.2

API форм

О документе

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

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

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

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

Чтобы создать экземпляр несвязанной Form, создайте экземпляр класса:

>>> f = ContactForm()

Чтобы связать данные с формой, передайте данные в виде словаря в качестве первого параметра конструктору вашего класса Form:

>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)

В этом словаре ключи — это имена полей, которые соответствуют атрибутам в вашем классе Form. Значения — это данные, которые вы пытаетесь валидировать. Обычно это строки, но нет требования, чтобы они были строками; тип данных, который вы передаёте, зависит от Field, как мы увидим чуть позже.

Form.is_bound

Если вам нужно отличить связанный экземпляр формы от несвязанного во время выполнения, проверьте значение атрибута формы is_bound:

>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({"subject": "hello"})
>>> f.is_bound
True

Обратите внимание, что передача пустого словаря создаёт связанную форму с пустыми данными:

>>> f = ContactForm({})
>>> f.is_bound
True

Если у вас есть связанный экземпляр Form и вы хотите как-то изменить данные, или если вы хотите связать несвязанный экземпляр Form с некоторыми данными, создайте другой экземпляр Form. Нет способа изменить данные в экземпляре Form. После создания экземпляра Form, следует считать его данные неизменяемыми, вне зависимости от наличия данных.

Использование форм для проверки данных

Form.clean()

Реализуйте метод clean() в вашем Form объекте, когда требуется добавить пользовательскую валидацию для взаимозависимых полей. Обратитесь к Очистка и проверка полей, зависящих друг от друга для примера использования.

Form.is_valid()

Основная задача объекта Form — валидация данных. Для привязанного экземпляра Form вызовите метод is_valid() для запуска проверки и получения булевого значения, указывающего, были ли данные валидными:

>>> data = {
...     "subject": "hello",
...     "message": "Hi there",
...     "sender": "foo@example.com",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
True

Давайте попробуем с невалидными данными. В этом случае, subject пусто (ошибка, так как все поля по умолчанию обязательны), а sender не является корректным адресом электронной почты:

>>> data = {
...     "subject": "",
...     "message": "Hi there",
...     "sender": "invalid email address",
...     "cc_myself": True,
... }
>>> f = ContactForm(data)
>>> f.is_valid()
False
Form.errors

Обратитесь к атрибуту errors для получения словаря сообщений об ошибках:

>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}

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

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

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

Form.errors.as_data()

Возвращает словарь, отображающий поля к их исходным 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 = ContactForm(auto_id=False)
>>> another_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, а не пустая строка. Более подробная информация о поведении каждого поля в этом случае представлена в примечании «Пустое значение» для каждого поля в разделе «Встроенные классы полей» ниже.

Вы можете написать код для выполнения валидации для определённых полей формы (на основе их имени) или для формы в целом (учитывая комбинации различных полей). Более подробная информация об этом в Валидация форм и полей.

Вывод форм в 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-тег для каждого тега берётся непосредственно из имени атрибута в классе ContactForm.
  • Текст метки для каждого поля, например, 'Subject:', 'Message:' и 'Cc myself:', генерируется из имени поля путём преобразования всех символов подчеркивания в пробелы и заглавной буквы первой буквы. Снова, обратите внимание, что это всего лишь разумные значения по умолчанию; вы также можете указать метки вручную.
  • Каждая метка окружена тегом HTML <label>, который ссылается на соответствующее поле формы через его id. Его id, в свою очередь, генерируется путём добавления префикса 'id_' к имени поля. Атрибуты id и теги <label> включаются в вывод по умолчанию для соблюдения лучших практик, но вы можете изменить это поведение.
  • Вывод использует синтаксис HTML5, ориентируясь на <!DOCTYPE html>. Например, он использует булевы атрибуты, такие как checked, а не стиль XHTML checked='checked'.

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

Стандартное отображение

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

template_name

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

get_context()

Form.get_context()

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

Доступные данные контекста:

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

template_name_label

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

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

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

Form.auto_id

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

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

Значения атрибута id генерируются путём добавления префикса id_ к именам полей формы. Однако этот параметр настраивается, если вы хотите изменить соглашение id или удалить атрибуты HTML id и теги <label> целиком.

Используйте аргумент auto_id конструктора Form для управления поведением id и меток. Этот аргумент должен быть True, False или строкой.

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

>>> f = ContactForm(auto_id=False)
>>> print(f)
<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,
... }
>>> ContactForm(data).as_div()

… даёт HTML, подобный этому:

<div>
  <label for="id_subject">Subject:</label>
  <ul class="errorlist" id="id_subject_error"><li>This field is required.</li></ul>
  <input type="text" name="subject" maxlength="100" required aria-invalid="true" aria-describedby="id_subject_error" id="id_subject">
</div>
<div>
  <label for="id_message">Message:</label>
  <textarea name="message" cols="40" rows="10" required id="id_message">Hi there</textarea>
</div>
<div>
  <label for="id_sender">Sender:</label>
  <ul class="errorlist" id="id_sender_error"><li>Enter a valid email address.</li></ul>
  <input type="email" name="sender" value="invalid email address" maxlength="320" required aria-invalid="true" aria-describedby="id_sender_error" 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>

Шаблоны форм Django по умолчанию связывают ошибки валидации с их входными данными, используя атрибут HTML aria-describedby, когда у поля есть auto_id и не указан настраиваемый aria-describedby. Если настраиваемый aria-describedby задан при определении виджета, это переопределит значение по умолчанию.

Если виджет отображается в <fieldset>, то aria-describedby добавляется к этому элементу, иначе он добавляется к HTML-элементу виджета (например, <input>).

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

aria-describedby был добавлен для связывания ошибок с их входными данными.

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

class ErrorList(initlist=None, error_class=None, renderer=None, field_id=None) [source]

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

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

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

error_class

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

renderer

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

field_id
Новое в Django 5.2.

id для поля, к которому относятся ошибки. Это позволяет добавить атрибут HTML id в шаблон ошибок и удобно связывать ошибки с полем. Шаблон по умолчанию использует формат id="{{ field_id }}_error", и значение предоставляется Form.add_error() с помощью auto_id поля.

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() [source]

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

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

  • 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 [source]

Используется для отображения HTML или доступа к атрибутам отдельного поля экземпляра Form.

Метод __str__() этого объекта отображает HTML для этого поля.

Можно использовать Form.bound_field_class и Field.bound_field_class для указания другого класса BoundField для формы или для отдельного поля соответственно.

См. Настройка BoundField для примеров переопределения BoundField.

Для получения отдельного 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.aria_describedby [source]
Добавлен в Django 5.2.

Возвращает ссылку aria-describedby для ассоциации поля с его текстом справки и ошибками. Возвращает None, если aria-describedby установлено в Widget.attrs, чтобы сохранить пользовательский атрибут при отрисовке формы.

BoundField.auto_id [source]

Атрибут HTML ID для этого BoundField. Возвращает пустую строку, если Form.auto_id установлено в False.

BoundField.data [source]

Это свойство возвращает данные для этого 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 [source]

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

BoundField.field

Экземпляр формы Field из класса формы, который оборачивает этот BoundField.

BoundField.form

Экземпляр Form, к которому привязан этот BoundField.

BoundField.help_text

Текст справки help_text поля.

BoundField.html_name

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

BoundField.id_for_label [source]

Используйте это свойство для отрисовки 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 [source]

Используйте 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 [source]

Возвращает 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 [source]

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

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

BoundField.use_fieldset [source]

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

BoundField.widget_type [source]

Возвращает имя класса обернутого виджета поля в нижнем регистре, с удаленными любыми хвостовыми 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()

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

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

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

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

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

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

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

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

BoundField.css_classes(extra_classes=None) [source]

При использовании коротких способов отображения Django, CSS классы используются для обозначения обязательных полей формы или полей, содержащих ошибки. Если вы вручную отображаете форму, вы можете получить доступ к этим CSS классам с помощью метода css_classes:

>>> f = ContactForm(data={"message": ""})
>>> f["message"].css_classes()
'required'

Если вы хотите добавить дополнительные классы помимо классов ошибок и обязательных полей, вы можете указать эти классы в качестве аргумента:

>>> f = ContactForm(data={"message": ""})
>>> f["message"].css_classes("foo bar")
'foo bar required'
BoundField.get_context() [source]

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

BoundField.label_tag(contents=None, attrs=None, label_suffix=None, tag=None) [source]

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

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

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

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

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

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

BoundField.value() [source]

Используйте этот метод для отображения исходного значения этого поля так, как это было бы отображено Widget:

>>> initial = {"subject": "welcome"}
>>> unbound_form = ContactForm(initial=initial)
>>> bound_form = ContactForm(data={"subject": "hi"}, initial=initial)
>>> print(unbound_form["subject"].value())
welcome
>>> print(bound_form["subject"].value())
hi

Настройка BoundField

Form.bound_field_class
Новое в Django 5.2.

Определите пользовательский класс BoundField для использования при рендеринге формы. Это имеет приоритет над классом на уровне проекта BaseRenderer.bound_field_class (вместе с пользовательским FORM_RENDERER), но может быть переопределён на уровне поля Field.bound_field_class.

Если не определён как переменная класса, bound_field_class можно установить через аргумент bound_field_class в конструкторе Form или Field.

По соображениям совместимости, пользовательское поле формы всё ещё может переопределить Field.get_bound_field() для использования пользовательского класса, хотя любой из предыдущих вариантов предпочтительнее.

Вы можете использовать пользовательский BoundField, если вам нужно получить дополнительную информацию о поле формы в шаблоне, а использование подкласса Field недостаточно.

Например, если у вас есть 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):
    bound_field_class = GPSCoordinatesBoundField

Теперь вы можете получить доступ к стране в шаблоне с помощью {{ form.coordinates.country }}.

Вы также можете настроить рендеринг шаблонов полей формы по умолчанию. Например, вы можете переопределить BoundField.label_tag() для добавления пользовательского класса:

class StyledLabelBoundField(BoundField):
    def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None):
        attrs = attrs or {}
        attrs["class"] = "wide"
        return super().label_tag(contents, attrs, label_suffix, tag)


class UserForm(forms.Form):
    bound_field_class = StyledLabelBoundField
    name = CharField()

Это обновит рендеринг формы по умолчанию:

>>> f = UserForm()
>>> print(f["name"].label_tag)
<label for="id_name" class="wide">Name:</label>

Чтобы добавить класс CSS к обертывающему HTML-элементу всех полей, можно переопределить BoundField, чтобы получить другое набора CSS-классов:

class WrappedBoundField(BoundField):
    def css_classes(self, extra_classes=None):
        parent_css_classes = super().css_classes(extra_classes)
        return f"field-class {parent_css_classes}".strip()


class UserForm(forms.Form):
    bound_field_class = WrappedBoundField
    name = CharField()

Это обновит рендеринг формы следующим образом:

>>> f = UserForm()
>>> print(f)
<div class="field-class"><label for="id_name">Name:</label><input type="text" name="name" required id="id_name"></div>

В качестве альтернативы, для переопределения класса BoundField на уровне проекта, BaseRenderer.bound_field_class можно определить в пользовательском FORM_RENDERER:

mysite/renderers.py
from django.forms.renderers import DjangoTemplates

from .forms import CustomBoundField


class CustomRenderer(DjangoTemplates):
    bound_field_class = CustomBoundField
settings.py
FORM_RENDERER = "mysite.renderers.CustomRenderer"

Связывание загруженных файлов с формой

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

Spec-Zone.ru

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