API форм

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

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

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

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

  • Если он привязан к набору данных, он способен проверить эти данные и отобразить форму как HTML с данными, отображаемыми в 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когда вы должны добавить настраиваемую проверку для взаимозависимых полей. См. Раздел Очистка и проверка полей, которые зависят друг от друга, например, использования.

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.

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

Form.errors.as_data()

Возвращает, dictкоторый сопоставляет поля с их исходными 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 , не связанных с конкретным полем. Это включает в себя ValidationErrors, которые возникают, 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!'})

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

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

>>> 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()метод на вашем, Formкогда вам нужно проверить, изменились ли данные формы по сравнению с исходными данными.

>>> 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нормализует ввод в datetime.dateобъект Python . Независимо от того, передаете ли вы ему строку в формате '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всегда будет содержать только ключ для полей, определенных в Form, даже если вы передадите дополнительные данные при определении Form. В этом примере мы передаем конструктору несколько дополнительных полей 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'}

Когда 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_nameis CharFieldи CharFields обрабатывают пустые значения как пустую строку. Каждому типу поля известно, какое у него «пустое» значение - например, для 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обозначается символами an и an . представлен расширением . Обратите внимание, что это просто разумные значения по умолчанию; вы можете указать, какой HTML использовать для данного поля, используя виджеты, которые мы вскоре объясним.<input type="text">EmailField<input type="email">BooleanField(null=False)<input type="checkbox">
  • HTML nameдля каждого тега берется непосредственно из имени его атрибута в ContactFormклассе.
  • Текстовая метка для каждого поля - например 'Subject:', 'Message:'и создается из имени поля путем преобразования всех подчеркиваний в пробелы и верхнего регистра первой буквы. Опять же, обратите внимание, что это просто разумные значения по умолчанию; вы также можете указать метки вручную.'Cc myself:'
  • Каждая текстовая метка окружена <label>тегом HTML , который указывает на соответствующее поле формы через свой id. Его id, в свою очередь, генерируется путем добавления 'id_'к имени поля. Эти id атрибуты и <label>теги включены в выводе по умолчанию, чтобы следовать рекомендациям, но вы можете изменить это поведение.
  • В выводе используется синтаксис HTML5, таргетинг . Например, он использует логические атрибуты, такие как, а не стиль XHTML .<!DOCTYPE html>checkedchecked='checked'

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

as_p()

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

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

Form.auto_id

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

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

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

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

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

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

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

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

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

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

Если auto_idустановлено любое другое истинное значение, такое как строка, которая не включает в себя, %sтогда библиотека будет действовать так, как если бы auto_idона была True.

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

Form.label_suffix

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

Можно настроить этот символ или полностью опустить его, используя label_suffixпараметр:

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

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

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

Form.use_required_attribute

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

Наборы форм создают экземпляры форм, use_required_attribute=Falseчтобы избежать неправильной проверки браузером при добавлении и удалении форм из набора форм.

Настройка отрисовки виджетов формы

Form.default_renderer

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

Вы можете установить это как атрибут класса при объявлении вашей формы или использовать rendererаргумент для Form.__init__(). Например:

from django import forms

class MyForm(forms.Form):
    default_renderer = MyRenderer()

или же:

form = MyForm(renderer=MyRenderer())

Примечания по порядку полей

В as_p(), as_ul()и as_table()ярлыки, поля отображаются в том порядке , в котором вы определяете их в классе формы. Например, в ContactFormпримере, поля определены в порядке subject, message, sender, cc_myself. Чтобы изменить порядок вывода HTML, измените порядок, в котором эти поля перечислены в классе.

Есть еще несколько способов изменить порядок:

Form.field_order

По умолчанию Form.field_order=None, который сохраняет порядок, в котором вы определяете поля в своем классе формы. Если field_orderэто список имен полей, поля упорядочиваются, как указано в списке, а оставшиеся поля добавляются в соответствии с порядком по умолчанию. Неизвестные имена полей в списке игнорируются. Это позволяет отключить поле в подклассе, установив для него значение, Noneбез необходимости переопределять порядок.

Вы также можете использовать Form.field_orderаргумент Formдля переопределения порядка полей. Если a Formопределяет и вы включаете при создании экземпляра , то последний будет иметь приоритет.field_order field_orderFormfield_order

Form.order_fields( field_order )

Вы можете изменить порядок полей в любое время, используя order_fields()список имен полей, как в field_order.

Как отображаются ошибки

Если вы визуализируете связанный Formобъект, процесс визуализации автоматически запускает проверку формы, если это еще не произошло, и вывод HTML будет включать ошибки проверки в виде рядом с полем. Конкретное расположение сообщений об ошибках зависит от используемого метода вывода:<ul class="errorlist">

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

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

По умолчанию формы используются 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">

Выходные данные для конкретного поля учитывают 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().

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

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

Отображает поле, отображая переданный виджет, добавляя любые атрибуты 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_tag()метод:

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

Вы можете указать contentsпараметр, который заменит автоматически созданный тег ярлыка. 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>элемент правильно определяет enctypeas "multipart/form-data":

<form enctype="multipart/form-data" method="post" action="/foo/">

Во-вторых, когда вы используете форму, вам нужно привязать данные файла. Данные файла обрабатываются отдельно от данных обычной формы, поэтому, когда ваша форма содержит FileFieldи ImageField, вам нужно будет указать второй аргумент при привязке формы. Итак, если мы расширим нашу ContactForm, чтобы включить ImageFieldвызываемый объект 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

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

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

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

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

Copyright ©2021 All rights reserved