API форм

Об этом документе

Этот документ подробно описывает Django Forms API. Рекомендуется сначала прочитать введение в использование форм .

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

Экземпляр Form либо привязан (привязан) к набору данных, либо не привязан (не привязан).

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

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

>>> f = ContactForm()

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

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': '[email protected]',
...         '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.is_valid()

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

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': '[email protected]',
...         '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 .

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

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 = Ложь )

Возвращать ошибки, сериализованные как JSON.

>>> f.errors.as_json()
{"sender": [{"message": "Enter a valid email address.", "code": "invalid"}],
"subject": [{"message": "This field is required.", "code": "required"}]}

По умолчанию as_json() не экранировать его содержимое. Если вы используете его в контексте, например, в запросах AJAX к представлению формы, где клиент интерпретирует ответ и вставляет ошибки на страницу, вам нужно обязательно экранировать содержимое на стороне клиента, чтобы избежать возможности атака с использованием межсайтовых сценариев. Вы можете сделать это в JavaScript с помощью или в jQuery с (а не его функцией ).element.textContent = errorText $(el).text(errorText) .html()

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

Form.errors.get_json_data( escape_html = Ложь )

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

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

Form.add_error( поле , ошибка )

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

Параметр field - это имя поля, которому будут присвоены ошибки. Если его значение равно None , ошибка рассматривается как ошибка, не связанная с полем, и будет одной из ошибок, возвращаемых функцией Form.non_field_errors() .

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

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

Form.has_error( поле , код = Нет )

Этот метод возвращает логическое значение, указывающее, содержит ли поле ошибку с 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 initial

>>> from django import forms
>>> class CommentForm(forms.Form):
...     name = forms.CharField(initial='class')
...     url = forms.URLField()
...     comment = forms.CharField()
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="instance" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" required></td></tr>
Form.get_initial_for_field( поле , имя_поля )

Используется get_initial_for_field() для получения исходных данных для поля формы. Данные берутся в Form.initial и Field.initial , в таком порядке, и оценивают любое исполняемое начальное значение, если таковые имеются.

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

Form.has_changed()

Если вам нужно узнать, какие данные формы были изменены по отношению к исходным данным, используйте метод has_changed() формы.

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': '[email protected]',
...         'cc_myself': True}
>>> f = ContactForm(data, initial=data)
>>> f.has_changed()
False

Когда форма отправляется, она перестраивается и предоставляются исходные данные, чтобы можно было провести сравнение:

>>> f = ContactForm(request.POST, initial=data)
>>> f.has_changed()

has_changed() возвращается, True если данные request.POST отличаются от того, что было предоставлено, в initial противном случае возвращается False . Результат получается путем вызова Field.has_changed() каждого поля формы.

Form.changed_data

Атрибут changed_data возвращает список имен полей, значения которых в данных с привязкой к форме (обычно request.POST ) отличаются от тех, которые изначально были предоставлены в initial . Возвращенный список пуст, если данные полностью идентичны.

>>> f = ContactForm(request.POST, initial=data)
>>> if f.has_changed():
...     print("The following fields changed: %s" % ", ".join(f.changed_data))
>>> f.changed_data
['subject', 'message']

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

Form.fields

Вы можете получить доступ к полям экземпляра Form из его атрибута fields :

>>> for row in f.fields.values(): print(row)
...
<django.forms.fields.CharField object at 0x7ffaac632510>
<django.forms.fields.URLField object at 0x7ffaac632f90>
<django.forms.fields.CharField object at 0x7ffaac3aa050>
>>> f.fields['name']
<django.forms.fields.CharField object at 0x7ffaac6324d0>

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

>>> f.as_table().split('\n')[0]
'<tr><th>Name:</th><td><input name="name" type="text" value="instance" required></td></tr>'
>>> f.fields['name'].label = "Username"
>>> f.as_table().split('\n')[0]
'<tr><th>Username:</th><td><input name="name" type="text" value="instance" required></td></tr>'

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

>>> f.base_fields['name'].label = "Username"
>>> another_f = CommentForm(auto_id=False)
>>> another_f.as_table().split('\n')[0]
'<tr><th>Username:</th><td><input name="name" type="text" value="class" required></td></tr>'

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

Form.cleaned_data

Каждое поле класса Form отвечает не только за проверку своих данных, но и за их «очистку», то есть их нормализацию в согласованном формате. Это очень полезная функция, поскольку она позволяет вводить данные поля несколькими способами, сохраняя при этом согласованность полученных данных.

Например, DateField нормализует ввод в объект Python datetime.date . Независимо от того, является ли передаваемый контент строкой формата '1994-07-15' , объектом datetime.date или каким-либо другим форматом, он DateField всегда будет превращать этот контент в объект datetime.date , пока он действителен.

После создания экземпляра Form с набором данных и его проверки можно получить доступ к очищенным данным по их атрибуту cleaned_data :

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': '[email protected]',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there', 'sender': '[email protected]', '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 всегда содержит только ключи, соответствующие полям, определенным в форме, даже если вы передаете ему дополнительные данные при создании формы. В этом примере мы передаем конструктору дополнительные данные поля ContactForm , но они cleaned_data содержат только те данные, которые соответствуют полям в форме:

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': '[email protected]',
...         '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': '[email protected]', 'subject': 'hello'}

Если форма действительна, 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 , и эти поля рассматривать пустую строку как пустое значение. Каждый тип поля знает свое пустое значение, например, DateField используйте None вместо пустой строки. Дополнительные сведения о поведении каждого поля в этом сценарии см. В разделе «Пустое значение» для каждого поля в разделе « Field Встроенные классы» ниже.

Можно написать код для выполнения проверки определенных полей формы (по их имени) или для всей формы (с учетом комбинации различных полей). Дополнительную информацию об этом можно найти в разделе «Проверка форм и полей» .

Отображение форм в HTML

Вторая задача объекта Form - отобразить себя в формате HTML. Для этого отобразите его с помощью print :

>>> f = ContactForm()
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>

Если форма привязана к данным, вывод HTML будет содержать эти данные должным образом. Например, если поле представлено компонентом , данные появятся в атрибуте . Если поле представлено компонентом , созданный HTML-код будет содержать, если применимо:<input type="text"> value <input type="checkbox"> checked

>>> data = {'subject': 'hello',
...         'message': 'Hi there',
...         'sender': '[email protected]',
...         'cc_myself': True}
>>> f = ContactForm(data)
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" value="[email protected]" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked></td></tr>

Этот вывод по умолчанию представляет собой HTML-таблицу с двумя столбцами, по одной строке <tr> на поле. Обратите внимание на это:

  • По маневренности причин результат не не содержит <table> и тег </table> , ни <form> , </form> или меток . Вы должны их предоставить.<input type="submit">
  • Каждый тип элемента управления имеет представление HTML по умолчанию. CharField представлена и с помощью . представлен . Обратите внимание, что это только разумные значения по умолчанию; можно определить HTML-код, создаваемый конкретным полем, с помощью компонентов, которые мы объясним позже.<input type="text"> EmailField <input type="email"> BooleanField(null=False) <input type="checkbox">
  • name HTML- имя каждого тега напрямую выводится из имени его атрибута в классе ContactForm .
  • Текстовая метка для каждого поля (например 'Subject:' , 'Message:' и ) создается из имени поля путем преобразования всех подчеркиваний в пробелы и использования первой буквы с заглавной буквы. Опять же, это просто более или менее адекватные значения по умолчанию; вы также можете определить эти метки вручную.'Cc myself:'
  • Каждая текстовая метка встроена в тег HTML, <label> который ссылается на свое поле формы по его атрибуту id . Значение этого параметра создается путем добавления префикса 'id_' к имени поля. Атрибуты id и теги <label> включаются в созданный HTML по умолчанию для лучшей практики, но вы можете изменить это поведение.
  • В результате используется синтаксис HTML5 с заголовком . Например, такие логические атрибуты предпочтительнее стиля XHTML .<!DOCTYPE html> checked checked='checked'

Хотя результат as <table> является стилем результата по умолчанию при отображении формы с print , доступны другие стили результата. Каждый стиль доступен для метода объекта формы, и каждый метод отрисовки возвращает строку.

as_p()

Form.as_p()

as_p() создает форму с рядом тегов <p> , каждый из которых содержит поле:

>>> f = ContactForm()
>>> f.as_p()
'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" required></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>'
>>> print(f.as_p())
<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>
<p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>

as_ul()

Form.as_ul()

as_ul() создает форму с серией тегов <li> , каждый из которых содержит поле. В <ul> и теги </ul> не включены, давая вам возможность определить атрибуты тега сами <ul> :

>>> f = ContactForm()
>>> f.as_ul()
'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>'
>>> print(f.as_ul())
<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>
<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>

as_table()

Form.as_table()

Наконец, as_table() создайте форму в теге HTML <table> . Это тот же результат, что и при его отображении print . Фактически, когда с ним отображается объект формы print , его метод as_table() вызывается в фоновом режиме:

>>> f = ContactForm()
>>> f.as_table()
'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>'
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>

Добавление стилей в обязательные или ошибочные строки формы

Form.error_css_class
Form.required_css_class

Довольно часто приходится определять определенные стили для строк и полей формы, которые являются обязательными или содержат ошибки. Например, мы можем выделить обязательные строки формы жирным шрифтом, а ошибки - красным.

Класс Form предлагает несколько точек входа для добавления атрибутов class в обязательные строки или строки с ошибками: заполните атрибуты Form.error_css_class иForm.required_css_class

from django import forms

class ContactForm(forms.Form):
    error_css_class = 'error'
    required_css_class = 'required'

    # ... and the rest of your fields here

После этого классы "error" и "required" будут присвоены соответствующим строкам. HTML-код будет выглядеть примерно так:

>>> f = ContactForm(data)
>>> print(f.as_table())
<tr class="required"><th><label class="required" for="id_subject">Subject:</label>    ...
<tr class="required"><th><label class="required" for="id_message">Message:</label>    ...
<tr class="required error"><th><label class="required" for="id_sender">Sender:</label>      ...
<tr><th><label for="id_cc_myself">Cc myself:<label> ...
>>> f['subject'].label_tag()
<label class="required" for="id_subject">Subject:</label>
>>> f['subject'].label_tag(attrs={'class': 'foo'})
<label for="id_subject" class="foo required">Subject:</label>

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

Form.auto_id

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

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

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

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

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

>>> f = ContactForm(auto_id=False)
>>> print(f.as_table())
<tr><th>Subject:</th><td><input type="text" name="subject" maxlength="100" required></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" required></td></tr>
<tr><th>Sender:</th><td><input type="email" name="sender" required></td></tr>
<tr><th>Cc myself:</th><td><input type="checkbox" name="cc_myself"></td></tr>
>>> print(f.as_ul())
<li>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <input type="text" name="message" required></li>
<li>Sender: <input type="email" name="sender" required></li>
<li>Cc myself: <input type="checkbox" name="cc_myself"></li>
>>> print(f.as_p())
<p>Subject: <input type="text" name="subject" maxlength="100" required></p>
<p>Message: <input type="text" name="message" required></p>
<p>Sender: <input type="email" name="sender" required></p>
<p>Cc myself: <input type="checkbox" name="cc_myself"></p>

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

>>> f = ContactForm(auto_id=True)
>>> print(f.as_table())
<tr><th><label for="subject">Subject:</label></th><td><input id="subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" required></td></tr>
<tr><th><label for="sender">Sender:</label></th><td><input type="email" name="sender" id="sender" required></td></tr>
<tr><th><label for="cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="cc_myself"></td></tr>
>>> print(f.as_ul())
<li><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="message">Message:</label> <input type="text" name="message" id="message" required></li>
<li><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" required></li>
<li><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself"></li>
>>> print(f.as_p())
<p><label for="subject">Subject:</label> <input id="subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="message">Message:</label> <input type="text" name="message" id="message" required></p>
<p><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" required></p>
<p><label for="cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="cc_myself"></p>

Если auto_id установлено значение строки, содержащей символ формата '%s' , HTML-рендеринг формы будет содержать теги <label> и выходные атрибуты id на основе строки формата. Например, для строки формата 'champ_%s' атрибут id поля с именем «тема» будет 'champ_sujet' . Продолжая наш пример:

>>> f = ContactForm(auto_id='id_for_%s')
>>> print(f.as_table())
<tr><th><label for="id_for_subject">Subject:</label></th><td><input id="id_for_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" required></td></tr>
<tr><th><label for="id_for_sender">Sender:</label></th><td><input type="email" name="sender" id="id_for_sender" required></td></tr>
<tr><th><label for="id_for_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></td></tr>
>>> print(f.as_ul())
<li><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" required></li>
<li><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" required></li>
<li><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li>
>>> print(f.as_p())
<p><label for="id_for_subject">Subject:</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" required></p>
<p><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" required></p>
<p><label for="id_for_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></p>

Если auto_id установлено любое другое значение, которое оценивается как «истина», например строка, не содержащая a %s , библиотека примет auto_id это значение True .

По умолчанию auto_id содержит значение 'id_%s' .

Form.label_suffix

Переводимая строка (по умолчанию - двоеточие ( : )), которая будет добавлена ​​к имени каждой метки при визуализации HTML-формы.

Этот символ можно настроить или полностью исключить с помощью параметра label_suffix :

>>> f = ContactForm(auto_id='id_for_%s', label_suffix='')
>>> print(f.as_ul())
<li><label for="id_for_subject">Subject</label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" required></li>
<li><label for="id_for_sender">Sender</label> <input type="email" name="sender" id="id_for_sender" required></li>
<li><label for="id_for_cc_myself">Cc myself</label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li>
>>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->')
>>> print(f.as_ul())
<li><label for="id_for_subject">Subject -></label> <input id="id_for_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" required></li>
<li><label for="id_for_sender">Sender -></label> <input type="email" name="sender" id="id_for_sender" required></li>
<li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself"></li>

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

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

Form.use_required_attribute

Если установлено значение 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 будет содержать ошибки проверки в виде раздела рядом с полем. Точное расположение сообщений об ошибках зависит от используемого метода рендеринга HTML:<ul class="errorlist">

>>> data = {'subject': '',
...         'message': 'Hi there',
...         'sender': 'invalid email address',
...         'cc_myself': True}
>>> f = ContactForm(data, auto_id=False)
>>> print(f.as_table())
<tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" required></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" value="Hi there" required></td></tr>
<tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid email address.</li></ul><input type="email" name="sender" value="invalid email address" required></td></tr>
<tr><th>Cc myself:</th><td><input checked type="checkbox" name="cc_myself"></td></tr>
>>> print(f.as_ul())
<li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <input type="text" name="message" value="Hi there" required></li>
<li><ul class="errorlist"><li>Enter a valid email address.</li></ul>Sender: <input type="email" name="sender" value="invalid email address" required></li>
<li>Cc myself: <input checked type="checkbox" name="cc_myself"></li>
>>> print(f.as_p())
<p><ul class="errorlist"><li>This field is required.</li></ul></p>
<p>Subject: <input type="text" name="subject" maxlength="100" required></p>
<p>Message: <input type="text" name="message" value="Hi there" required></p>
<p><ul class="errorlist"><li>Enter a valid email address.</li></ul></p>
<p>Sender: <input type="email" name="sender" value="invalid email address" required></p>
<p>Cc myself: <input checked type="checkbox" name="cc_myself"></p>

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

По умолчанию формы используют django.forms.utils.ErrorList для форматирования ошибки проверки. Если вы хотите использовать другой класс для отображения ошибок, вы можете указать это при построении формы.

>>> from django.forms.utils import ErrorList
>>> class DivErrorList(ErrorList):
...     def __str__(self):
...         return self.as_divs()
...     def as_divs(self):
...         if not self: return ''
...         return '<div class="errorlist">%s</div>' % ''.join(['<div class="error">%s</div>' % e for e in self])
>>> f = ContactForm(data, auto_id=False, error_class=DivErrorList)
>>> f.as_p()
<div class="errorlist"><div class="error">This field is required.</div></div>
<p>Subject: <input type="text" name="subject" maxlength="100" required></p>
<p>Message: <input type="text" name="message" value="Hi there" required></p>
<div class="errorlist"><div class="error">Enter a valid email address.</div></div>
<p>Sender: <input type="email" name="sender" value="invalid email address" required></p>
<p>Cc myself: <input checked type="checkbox" name="cc_myself"></p>

Более тонкий дисплей

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

класс 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">

Конкретный результат HTML для каждого поля соответствует настройке auto_id объекта формы:

>>> f = ContactForm(auto_id=False)
>>> print(f['message'])
<input type="text" name="message" required>
>>> f = ContactForm(auto_id='id_%s')
>>> print(f['message'])
<input type="text" name="message" id="id_message" required>

Атрибуты BoundField

BoundField.auto_id

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

BoundField.data

Это свойство возвращает данные для этого объекта, BoundField полученные методом компонента value_from_datadict() , или None если он не был указан:

>>> unbound_form = ContactForm()
>>> print(unbound_form['subject'].data)
None
>>> bound_form = ContactForm(data={'subject': 'My Subject'})
>>> print(bound_form['subject'].data)
My Subject
BoundField.errors

Объект , связанный со списком , который отображается секцией при отображении в HTML:<ul class="errorlist">

>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
>>> f = ContactForm(data, auto_id=False)
>>> print(f['message'])
<input type="text" name="message" required>
>>> f['message'].errors
['This field is required.']
>>> print(f['message'].errors)
<ul class="errorlist"><li>This field is required.</li></ul>
>>> f['subject'].errors
[]
>>> print(f['subject'].errors)

>>> str(f['subject'].errors)
''
BoundField.field

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

BoundField.form

Экземпляр, Form с которым связан этот объект BoundField .

BoundField.help_text

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

BoundField.html_name

Имя, которое будет использоваться в атрибуте name HTML-кода компонента. При этом учитывается ценность prefix формы.

BoundField.id_for_label

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

<label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}

По умолчанию это будет имя поля с префиксом id_ («  id_my_field  » в примере выше). Этот идентификатор можно изменить, заполнив attrs компонент элемента управления. Например, определение такого поля:

my_field = forms.CharField(widget=forms.TextInput(attrs={'id': 'myFIELD'}))

и используя шаблон выше, вывод будет примерно таким:

<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" required>
BoundField.is_hidden

Возвращает True , является ли компонент этого объекта BoundField невидимым.

BoundField.label

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

BoundField.name

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

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

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

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

Методы BoundField

BoundField.as_hidden( attrs = Нет , ** kwargs )

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

**kwargs ретранслируется в as_widget() .

Этот метод в основном используется внутри компании. Вместо этого лучше использовать компонент ( widget ).

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

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

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

BoundField.css_classes( extra_classes = Нет )

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

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

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

>>> f = ContactForm(data={'message': ''})
>>> f['message'].css_classes('foo bar')
'foo bar required'
BoundField.label_tag( Не содержимое = нет , ATTRS = нет , label_suffix = None )

Чтобы отобразить тег label поля формы отдельно , мы можем вызвать его метод label_tag() :

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

Можно указать параметр, contents который заменит label автоматически сгенерированный тег . Словарь attrs может содержать дополнительные атрибуты тега <label> .

Сгенерированный HTML-код включает значение label_suffix формы (символ двоеточия по умолчанию) или, если определено, значение label_suffix конкретного поля. label_suffix Необязательный параметр позволяет вам переопределить любой суффикс, определенный ранее. Например, вы можете использовать пустую строку, чтобы скрыть метку для определенных полей. Если вам нужно сделать это в шаблоне, можно написать собственный фильтр, чтобы вы могли передавать параметры в label_tag .

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 и имя поля. Возвращенное значение будет использоваться для доступа к полю в шаблоне. Скорее всего, это будет экземпляр подкласса 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': '[email protected]',
...         'cc_myself': True}
>>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <file data>)}
>>> f = ContactFormWithMugshot(data, file_data)

На практике вы обычно указываете request.FILES в качестве источника данных файла (как для request.POST представления источника данных формы):

# Bound form with an image field, data from the request
>>> f = ContactFormWithMugshot(request.POST, request.FILES)

Конструкция несвязанной формы не меняется, просто опускаются как данные формы, так и данные файла:

# Unbound form with an image field
>>> f = ContactFormWithMugshot()

Обнаружение составных форм

Form.is_multipart()

Если вы пишете многоразовые представления или шаблоны, могут быть случаи, когда заранее неизвестно, является ли форма составной. Метод is_multipart() указывает, требует ли форма составного кодирования при отправке:

>>> f = ContactFormWithMugshot()
>>> f.is_multipart()
True

Вот пример того, как использовать этот метод в шаблоне:

{% if form.is_multipart %}
    <form enctype="multipart/form-data" method="post" action="/foo/">
{% else %}
    <form method="post" action="/foo/">
{% endif %}
{{ form }}
</form>

Формы и подклассы

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

При наследовании от Form настраиваемого класса результирующий подкласс включает все поля из его родительских классов, за которыми следуют поля, определенные в подклассе.

В этом примере ContactFormWithPriority содержит все поля ContactForm плюс дополнительное поле priority . Поля ContactForm появляются первыми:

>>> class ContactFormWithPriority(ContactForm):
...     priority = forms.CharField()
>>> f = ContactFormWithPriority(auto_id=False)
>>> print(f.as_ul())
<li>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <input type="text" name="message" required></li>
<li>Sender: <input type="email" name="sender" required></li>
<li>Cc myself: <input type="checkbox" name="cc_myself"></li>
<li>Priority: <input type="text" name="priority" required></li>

Возможно наследование от нескольких форм, считая эти формы «миксинами». В этом примере BeatleForm наследуется от PersonForm и InstrumentForm (в указанном порядке), а его список полей содержит поля от его родительских классов:

>>> from django import forms
>>> class PersonForm(forms.Form):
...     first_name = forms.CharField()
...     last_name = forms.CharField()
>>> class InstrumentForm(forms.Form):
...     instrument = forms.CharField()
>>> class BeatleForm(InstrumentForm, PersonForm):
...     haircut_type = forms.CharField()
>>> b = BeatleForm(auto_id=False)
>>> print(b.as_ul())
<li>First name: <input type="text" name="first_name" required></li>
<li>Last name: <input type="text" name="last_name" required></li>
<li>Instrument: <input type="text" name="instrument" required></li>
<li>Haircut type: <input type="text" name="haircut_type" required></li>

Можно декларативно удалить поле, Field унаследованное от родительского класса, задав его имя None в подклассе. Например :

>>> from django import forms

>>> class ParentForm(forms.Form):
...     name = forms.CharField()
...     age = forms.IntegerField()

>>> class ChildForm(ParentForm):
...     name = None

>>> list(ChildForm().fields)
['age']

Префиксы форм

Form.prefix

Тег <form> может содержать несколько форм Django. Чтобы каждая форма имела собственное пространство имен, используйте именованный параметр prefix :

>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
>>> print(mother.as_ul())
<li><label for="id_mother-first_name">First name:</label> <input type="text" name="mother-first_name" id="id_mother-first_name" required></li>
<li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" required></li>
>>> print(father.as_ul())
<li><label for="id_father-first_name">First name:</label> <input type="text" name="father-first_name" id="id_father-first_name" required></li>
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" required></li>

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

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

Copyright ©2020 All rights reserved