API форм¶
Об этом документе
В этом документе рассматриваются детали API форм Django. Сначала вам следует прочитать introduction to working with forms.
Связанные и несвязанные формы¶
Экземпляр Form
либо связан с набором данных, либо не связан.
- Если он связан с набором данных, он способен проверить эти данные и вывести форму в виде HTML с отображением данных в HTML.
- Если это unbound, он не может выполнить валидацию (потому что нет данных для валидации!), но он все еще может отобразить пустую форму как HTML.
-
class
Form
[исходный код]¶
Чтобы создать несвязанный экземпляр Form
, инстанцируйте класс:
>>> f = ContactForm()
Чтобы привязать данные к форме, передайте их в виде словаря в качестве первого параметра в конструктор вашего класса Form
:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
В этом словаре ключами являются имена полей, которые соответствуют атрибутам в вашем классе Form
. Значения - это данные, которые вы пытаетесь проверить. Обычно это строки, но нет требования, чтобы они были строками; тип передаваемых данных зависит от Field
, как мы увидим через некоторое время.
-
Form.
is_bound
¶
Если вам необходимо различать связанные и несвязанные экземпляры формы во время выполнения, проверьте значение атрибута формы is_bound
:
>>> f = ContactForm()
>>> f.is_bound
False
>>> f = ContactForm({'subject': 'hello'})
>>> f.is_bound
True
Обратите внимание, что передача пустого словаря создает связанную форму с пустыми данными:
>>> f = ContactForm({})
>>> f.is_bound
True
Если у вас есть связанный экземпляр Form
и вы хотите как-то изменить данные, или если вы хотите связать несвязанный экземпляр Form
с какими-то данными, создайте еще один экземпляр Form
. Не существует способа изменить данные в экземпляре Form
. После создания экземпляра Form
следует считать его данные неизменяемыми, независимо от того, есть у него данные или нет.
Использование форм для проверки данных¶
-
Form.
clean
()¶
Реализуйте метод clean()
на вашем Form
, когда вам необходимо добавить пользовательскую валидацию для полей, которые являются взаимозависимыми. Пример использования см. в Очистка и проверка полей, которые зависят друг от друга.
-
Form.
is_valid
()¶
Основная задача объекта Form
заключается в проверке данных. При наличии связанного экземпляра Form
вызовите метод is_valid()
, чтобы запустить проверку и вернуть булево значение, указывающее, были ли данные достоверными:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
Давайте попробуем с недействительными данными. В данном случае subject
пуст (ошибка, так как по умолчанию все поля обязательны для заполнения), а sender
не является действительным адресом электронной почты:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid email address',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
-
Form.
errors
¶
Обратитесь к атрибуту errors
, чтобы получить словарь сообщений об ошибках:
>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}
В этом словаре ключами являются имена полей, а значениями - списки строк, представляющих сообщения об ошибках. Сообщения об ошибках хранятся в виде списков, поскольку одно поле может иметь несколько сообщений об ошибках.
Вы можете получить доступ к errors
без необходимости сначала вызывать is_valid()
. Данные формы будут проверены при первом вызове is_valid()
или обращении к errors
.
Процедура валидации будет вызвана только один раз, независимо от того, сколько раз вы обращаетесь к errors
или вызываете is_valid()
. Это означает, что если валидация имеет побочные эффекты, то эти побочные эффекты будут вызваны только один раз.
-
Form.errors.
as_data
()¶
Возвращает 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=False)¶
Возвращает ошибки, сериализованные в виде JSON.
>>> f.errors.as_json()
{"sender": [{"message": "Enter a valid email address.", "code": "invalid"}],
"subject": [{"message": "This field is required.", "code": "required"}]}
По умолчанию as_json()
не экранирует свой вывод. Если вы используете его для чего-то вроде AJAX-запросов к форме представления, где клиент интерпретирует ответ и вставляет ошибки на страницу, вы захотите убедиться, что результаты на стороне клиента экранированы, чтобы избежать возможности межсайтовой скриптинг-атаки. Вы можете сделать это в JavaScript с помощью element.textContent = errorText
или с помощью $(el).text(errorText)
в jQuery (а не его функции .html()
).
Если по какой-то причине вы не хотите использовать экранирование на стороне клиента, вы также можете установить escape_html=True
, и сообщения об ошибках будут экранированы, чтобы вы могли использовать их непосредственно в HTML.
-
Form.errors.
get_json_data
(escape_html=False)¶
Возвращает ошибки в виде словаря, пригодного для сериализации в JSON. Form.errors.as_json()
возвращает сериализованный JSON, в то время как это возвращает данные об ошибках до их сериализации.
Параметр escape_html
ведет себя так, как описано в Form.errors.as_json()
.
-
Form.
add_error
(field, error)¶
Этот метод позволяет добавлять ошибки в определенные поля из метода Form.clean()
или вообще извне формы, например, из представления.
Аргумент field
является именем поля, к которому должны быть добавлены ошибки. Если его значение равно None
, то ошибка будет рассматриваться как неполевая ошибка, возвращаемая Form.non_field_errors()
.
Аргумент error
может быть строкой или, предпочтительно, экземпляром ValidationError
. См. раздел Поднятие ValidationError о лучших практиках при определении ошибок формы.
Обратите внимание, что Form.add_error()
автоматически удаляет соответствующее поле из cleaned_data
.
-
Form.
has_error
(field, code=None)¶
Этот метод возвращает булево число, обозначающее, есть ли в поле ошибка с конкретной ошибкой code
. Если code
- None
, то он вернет True
, если поле вообще содержит какие-либо ошибки.
Для проверки ошибок, не связанных с полем, используйте NON_FIELD_ERRORS
в качестве параметра field
.
-
Form.
non_field_errors
()¶
Этот метод возвращает список ошибок из Form.errors
, которые не связаны с конкретным полем. Сюда входят ValidationError
ошибки, возникающие в Form.clean()
и ошибки, добавленные с помощью Form.add_error(None, "...")
.
Поведение несвязанных форм¶
Бессмысленно проверять форму без данных, но, для справки, вот что происходит с несвязанными формами:
>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
Initial form values¶
-
Form.
initial
¶
Используйте initial
для объявления начального значения полей формы во время выполнения. Например, вы можете захотеть заполнить поле username
именем пользователя текущей сессии.
Чтобы добиться этого, используйте аргумент initial
для Form
. Этот аргумент, если он задан, должен представлять собой словарь, отображающий имена полей на начальные значения. Включите только те поля, для которых вы указываете начальное значение; нет необходимости включать каждое поле в вашу форму. Например:
>>> f = ContactForm(initial={'subject': 'Hi there!'})
Эти значения отображаются только для несвязанных форм, и они не используются в качестве резервных значений, если конкретное значение не предоставлено.
Если Field
определяет initial
и вы включаете initial
при инстанцировании Form
, то последний initial
будет иметь приоритет. В данном примере initial
предоставляется как на уровне поля, так и на уровне экземпляра формы, и последний имеет приоритет:
>>> from django import forms
>>> class CommentForm(forms.Form):
... name = forms.CharField(initial='class')
... url = forms.URLField()
... comment = forms.CharField()
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
>>> print(f)
<tr><th>Name:</th><td><input type="text" name="name" value="instance" required></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" required></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" required></td></tr>
-
Form.
get_initial_for_field
(field, field_name)¶
Returns the initial data for a form field. It retrieves the data from
Form.initial
if present, otherwise trying Field.initial
.
Callable values are evaluated.
Рекомендуется использовать BoundField.initial
вместо get_initial_for_field()
, поскольку BoundField.initial
имеет более простой интерфейс. Кроме того, в отличие от get_initial_for_field()
, BoundField.initial
кэширует свои значения. Это особенно полезно при работе с callables, возвращаемые значения которых могут меняться (например, datetime.now
или uuid.uuid4
):
>>> import uuid
>>> class UUIDCommentForm(CommentForm):
... identifier = forms.UUIDField(initial=uuid.uuid4)
>>> f = UUIDCommentForm()
>>> f.get_initial_for_field(f.fields['identifier'], 'identifier')
UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334')
>>> f.get_initial_for_field(f.fields['identifier'], 'identifier')
UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0')
>>> # Using BoundField.initial, for comparison
>>> f['identifier'].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
>>> f['identifier'].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
Проверка того, какие данные формы были изменены¶
-
Form.
has_changed
()¶
Используйте метод has_changed()
на вашем Form
, когда вам нужно проверить, были ли данные формы изменены по сравнению с начальными данными.
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data, initial=data)
>>> f.has_changed()
False
Когда форма отправлена, мы реконструируем ее и предоставляем исходные данные, чтобы можно было провести сравнение:
>>> f = ContactForm(request.POST, initial=data)
>>> f.has_changed()
has_changed()
будет True
, если данные из request.POST
отличаются от тех, что были предоставлены в initial
или False
в противном случае. Результат вычисляется путем вызова Field.has_changed()
для каждого поля формы.
-
Form.
changed_data
¶
Атрибут changed_data
возвращает список имен полей, значения которых в связанных данных формы (обычно request.POST
) отличаются от того, что было предоставлено в initial
. Он возвращает пустой список, если данные не отличаются.
>>> f = ContactForm(request.POST, initial=data)
>>> if f.has_changed():
... print("The following fields changed: %s" % ", ".join(f.changed_data))
>>> f.changed_data
['subject', 'message']
Доступ к полям из формы¶
-
Form.
fields
¶
Вы можете получить доступ к полям экземпляра Form
из его атрибута fields
:
>>> for row in f.fields.values(): print(row)
...
<django.forms.fields.CharField object at 0x7ffaac632510>
<django.forms.fields.URLField object at 0x7ffaac632f90>
<django.forms.fields.CharField object at 0x7ffaac3aa050>
>>> f.fields['name']
<django.forms.fields.CharField object at 0x7ffaac6324d0>
You can alter the field and BoundField
of Form
instance to
change the way it is presented in the form:
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
>>> f["subject"].label = "Topic"
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Topic:</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
Остерегайтесь изменять атрибут base_fields
, поскольку это изменение повлияет на все последующие ContactForm
экземпляры в рамках одного процесса Python:
>>> f.base_fields["subject"].label_suffix = "?"
>>> another_f = CommentForm(auto_id=False)
>>> f.as_div().split("</div>")[0]
'<div><label for="id_subject">Subject?</label><input type="text" name="subject" maxlength="100" required id="id_subject">'
Доступ к «чистым» данным¶
-
Form.
cleaned_data
¶
Каждое поле в классе Form
отвечает не только за проверку данных, но и за их «очистку» - нормализацию до согласованного формата. Это хорошая особенность, поскольку она позволяет вводить данные для конкретного поля различными способами, всегда приводя к согласованному результату.
Например, DateField
нормализует входные данные в объект Python datetime.date
. Независимо от того, передаете ли вы ему строку в формате '1994-07-15'
, объект datetime.date
или ряд других форматов, DateField
всегда нормализует ее в объект datetime.date
, пока он действителен.
После создания экземпляра Form
с набором данных и его проверки, вы можете получить доступ к чистым данным через его cleaned_data
атрибут:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
Обратите внимание, что любое текстовое поле - такое как CharField
или EmailField
- всегда очищает вводимые данные в строку. Мы рассмотрим последствия кодирования позже в этом документе.
Если ваши данные не проходят валидацию, словарь cleaned_data
содержит только валидные поля:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid email address',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> f.is_valid()
False
>>> f.cleaned_data
{'cc_myself': True, 'message': 'Hi there'}
cleaned_data
всегда только будет содержать ключ для полей, определенных в Form
, даже если вы передадите дополнительные данные при определении Form
. В этом примере мы передаем кучу дополнительных полей в конструктор ContactForm
, но cleaned_data
содержит только поля формы:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True,
... 'extra_field_1': 'foo',
... 'extra_field_2': 'bar',
... 'extra_field_3': 'baz'}
>>> f = ContactForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
Когда Form
действителен, cleaned_data
будет включать ключ и значение для всех своих полей, даже если данные не включали значение для некоторых необязательных полей. В этом примере словарь данных не включает значение для поля nick_name
, но cleaned_data
включает его, с пустым значением:
>>> from django import forms
>>> class OptionalPersonForm(forms.Form):
... first_name = forms.CharField()
... last_name = forms.CharField()
... nick_name = forms.CharField(required=False)
>>> data = {'first_name': 'John', 'last_name': 'Lennon'}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}
В этом примере значение cleaned_data
для nick_name
установлено в пустую строку, потому что nick_name
- это CharField
, а CharField
s рассматривает пустые значения как пустую строку. Каждый тип поля знает, что такое «пустое» значение - например, для DateField
это None
вместо пустой строки. Для получения подробной информации о поведении каждого поля в этом случае, смотрите примечание «Пустое значение» для каждого поля в разделе «Встроенные классы Field
» ниже.
Вы можете написать код для выполнения валидации для отдельных полей формы (на основе их названия) или для формы в целом (учитывая комбинации различных полей). Более подробная информация об этом содержится в Валидация форм и полей.
Вывод форм в формате HTML¶
Вторая задача объекта Form
- отобразить себя как HTML. Для этого, print
он:
>>> f = ContactForm()
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>
Если форма связана с данными, то HTML-вывод будет включать эти данные соответствующим образом. Например, если поле представлено символом <input type="text">
, то данные будут находиться в атрибуте value
. Если поле представлено символом <input type="checkbox">
, то HTML-вывод будет включать checked
, если это уместно:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" value="hello" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" value="foo@example.com" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" checked></td></tr>
Этот вывод по умолчанию представляет собой двухколоночную HTML-таблицу, с <tr>
для каждого поля. Обратите внимание на следующее:
- Для гибкости вывод не включает теги
<table>
и</table>
, а также теги<form>
и</form>
или тег<input type="submit">
. Это ваша работа, чтобы сделать это. - Каждый тип поля имеет HTML-представление по умолчанию.
CharField
представляется символом<input type="text">
, аEmailField
-<input type="email">
.BooleanField(null=False)
представляется символом<input type="checkbox">
. Обратите внимание, что это всего лишь разумные значения по умолчанию; вы можете указать, какой HTML использовать для данного поля, используя виджеты, о которых мы расскажем в ближайшее время. - HTML
name
для каждого тега берется непосредственно из имени его атрибута в классеContactForm
. - Текстовая метка для каждого поля - например,
'Subject:'
,'Message:'
и'Cc myself:'
- генерируется из имени поля путем преобразования всех знаков подчеркивания в пробелы и перевода первой буквы в верхний регистр. Еще раз отметим, что это всего лишь разумные значения по умолчанию; вы также можете задать метки вручную. - Каждая текстовая метка окружена тегом HTML
<label>
, который указывает на соответствующее поле формы через егоid
. Егоid
, в свою очередь, формируется путем добавления'id_'
к имени поля. Атрибутыid
и теги<label>
включаются в вывод по умолчанию, чтобы следовать лучшим практикам, но вы можете изменить это поведение. - При выводе используется синтаксис HTML5, ориентированный на
<!DOCTYPE html>
. Например, он использует булевы атрибуты, такие какchecked
, а не стиль XHTMLchecked='checked'
.
Хотя вывод <table>
является стилем вывода по умолчанию, когда вы print
форму, доступны и другие стили вывода. Каждый стиль доступен как метод на объекте формы, и каждый метод вывода возвращает строку.
Рендеринг по умолчанию¶
Рендеринг по умолчанию при print
форме использует следующие методы и атрибуты.
template_name
¶
-
Form.
template_name
¶
Имя шаблона, отображаемого при преобразовании формы в строку, например, через print(form)
или в шаблоне через {{ form }}
.
По умолчанию свойство, возвращающее значение form_template_name
рендерера. Вы можете задать его как строковое имя шаблона, чтобы переопределить его для конкретного класса формы.
В старых версиях template_name
по умолчанию использовалось строковое значение 'django/forms/default.html'
.
render()
¶
-
Form.
render
(template_name=None, context=None, renderer=None)¶
Метод render вызывается методом __str__
, а также методами Form.as_table()
, Form.as_p()
и Form.as_ul()
. Все аргументы являются необязательными и используются по умолчанию:
template_name
:Form.template_name
context
: Значение, возвращаемоеForm.get_context()
renderer
: Значение, возвращаемоеForm.default_renderer
Передавая template_name
, вы можете настроить шаблон, используемый только для одного вызова.
get_context()
¶
-
Form.
get_context
()¶
Return the template context for rendering the form.
Доступный контекст:
form
: Связанная форма.fields
: Все связанные поля, кроме скрытых.hidden_fields
: Все скрытые связанные поля.errors
: Все ошибки формы, не связанные с полями или скрытыми полями.
template_name_label
¶
-
Form.
template_name_label
¶
The template used to render a field’s <label>
, used when calling
BoundField.label_tag()
/legend_tag()
. Can be changed per
form by overriding this attribute or more generally by overriding the default
template, see also Overriding built-in form templates.
Стили вывода¶
Помимо непосредственного отображения формы, например, в шаблоне с {{ form }}
, следующие вспомогательные функции служат в качестве прокси для Form.render()
, передавая определенное значение template_name
.
Эти помощники наиболее полезны в шаблоне, когда вам нужно переопределить рендерер формы или значение, предоставляемое формой, но вы не можете передать дополнительный параметр в render()
. Например, вы можете отобразить форму в виде неупорядоченного списка с помощью {{ form.as_ul }}
.
Каждый помощник сопрягает метод формы с атрибутом, задающим соответствующее имя шаблона.
as_div()
¶
-
Form.
template_name_div
¶
Шаблон, используемый as_div()
. По умолчанию: 'django/forms/div.html'
.
-
Form.
as_div
()¶
as_div()
renders the form as a series of <div>
elements, with each
<div>
containing one field, such as:
>>> f = ContactForm()
>>> f.as_div()
… дает HTML как:
<div>
<label for="id_subject">Subject:</label>
<input type="text" name="subject" maxlength="100" required id="id_subject">
</div>
<div>
<label for="id_message">Message:</label>
<input type="text" name="message" required id="id_message">
</div>
<div>
<label for="id_sender">Sender:</label>
<input type="email" name="sender" required id="id_sender">
</div>
<div>
<label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself">
</div>
Примечание
Из шаблонов и стилей вывода, предоставляемых каркасом, рекомендуется as_div()
, а не as_p()
, as_table()
и as_ul()
, поскольку в этом шаблоне реализованы <fieldset>
и <legend>
для группировки связанных вводимых данных, и пользователям программы чтения с экрана легче ориентироваться.
as_p()
¶
-
Form.
template_name_p
¶
Шаблон, используемый as_p()
. По умолчанию: 'django/forms/p.html'
.
-
Form.
as_p
()¶
as_p()
отображает форму как серию тегов <p>
, каждый <p>
содержит одно поле:
>>> f = ContactForm()
>>> f.as_p()
'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" required></p>\n<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>'
>>> print(f.as_p())
<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></p>
<p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></p>
as_ul()
¶
-
Form.
template_name_ul
¶
Шаблон, используемый as_ul()
. По умолчанию: 'django/forms/ul.html'
.
-
Form.
as_ul
()¶
as_ul()
renders the form as a series of <li>
tags, with each <li>
containing one field. It does not include the <ul>
or </ul>
, so that
you can specify any HTML attributes on the <ul>
for flexibility:
>>> f = ContactForm()
>>> f.as_ul()
'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>\n<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>'
>>> print(f.as_ul())
<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" required></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" required></li>
<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" required></li>
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself"></li>
as_table()
¶
-
Form.
template_name_table
¶
Шаблон, используемый as_table()
. По умолчанию: 'django/forms/table.html'
.
-
Form.
as_table
()¶
as_table()
отображает форму в виде HTML <table>
:
>>> f = ContactForm()
>>> f.as_table()
'<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>'
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" required></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" required></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" required></td></tr>
<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself"></td></tr>
Стилизация требуемых или ошибочных строк формы¶
-
Form.
error_css_class
¶
-
Form.
required_css_class
¶
Довольно часто требуется стилизовать строки формы и поля, которые являются обязательными или содержат ошибки. Например, вы можете выделить обязательные строки формы жирным шрифтом, а ошибки - красным.
Класс Form
имеет пару крючков, которые можно использовать для добавления атрибутов class
к необходимым строкам или к строкам с ошибками: установить атрибуты Form.error_css_class
и/или Form.required_css_class
:
from django import forms
class ContactForm(forms.Form):
error_css_class = 'error'
required_css_class = 'required'
# ... and the rest of your fields here
После этого строкам будут присвоены классы "error"
и/или "required"
, по мере необходимости. HTML будет выглядеть примерно так:
>>> f = ContactForm(data)
>>> print(f.as_table())
<tr class="required"><th><label class="required" for="id_subject">Subject:</label> ...
<tr class="required"><th><label class="required" for="id_message">Message:</label> ...
<tr class="required error"><th><label class="required" for="id_sender">Sender:</label> ...
<tr><th><label for="id_cc_myself">Cc myself:<label> ...
>>> f['subject'].label_tag()
<label class="required" for="id_subject">Subject:</label>
>>> f['subject'].legend_tag()
<legend class="required" for="id_subject">Subject:</legend>
>>> f['subject'].label_tag(attrs={'class': 'foo'})
<label for="id_subject" class="foo required">Subject:</label>
>>> f['subject'].legend_tag(attrs={'class': 'foo'})
<legend for="id_subject" class="foo required">Subject:</legend>
Настройка атрибутов HTML id
и тегов <label>
элементов формы¶
-
Form.
auto_id
¶
По умолчанию методы рендеринга формы включают:
- Атрибуты HTML
id
на элементах формы. - Соответствующие теги
<label>
окружают метки. Тег HTML<label>
указывает, какой текст метки связан с каким элементом формы. Это небольшое усовершенствование делает формы более удобными для использования и более доступными для вспомогательных устройств. Всегда полезно использовать теги<label>
.
Значения атрибутов id
генерируются путем добавления id_
к именам полей формы. Однако это поведение можно настроить, если вы хотите изменить соглашение id
или полностью удалить атрибуты HTML id
и теги <label>
.
Используйте аргумент auto_id
в конструкторе Form
для управления поведением id
и метки. Этот аргумент должен быть True
, False
или строкой.
Если auto_id
равно False
, то вывод формы не будет включать ни <label>
тегов, ни id
атрибутов:
>>> f = ContactForm(auto_id=False)
>>> print(f.as_div())
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
<div>Sender:<input type="email" name="sender" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself"></div>
Если auto_id
установлено в True
, то вывод формы будет включать <label>
теги и будет использовать имя поля в качестве id
для каждого поля формы:
>>> f = ContactForm(auto_id=True)
>>> print(f.as_div())
<div><label for="subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="subject"></div>
<div><label for="message">Message:</label><textarea name="message" cols="40" rows="10" required id="message"></textarea></div>
<div><label for="sender">Sender:</label><input type="email" name="sender" required id="sender"></div>
<div><label for="cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="cc_myself"></div>
Если auto_id
установлен в строку, содержащую символ формата '%s'
, то вывод формы будет включать теги <label>
и генерировать атрибуты id
на основе строки формата. Например, для строки формата 'field_%s'
, поле с именем subject
получит id
значение 'field_subject'
. Продолжая наш пример:
>>> f = ContactForm(auto_id='id_for_%s')
>>> print(f.as_div())
<div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message:</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender:</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself:</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>
Если auto_id
установлено в любое другое истинное значение - например, в строку, которая не включает %s
- то библиотека будет действовать так, как будто auto_id
- это True
.
По умолчанию auto_id
устанавливается в строку 'id_%s'
.
-
Form.
label_suffix
¶
Переводимая строка (по умолчанию двоеточие (:
) на английском языке), которая будет добавлена после любого имени метки при отображении формы.
Можно настроить этот символ или полностью его пропустить, используя параметр label_suffix
:
>>> f = ContactForm(auto_id='id_for_%s', label_suffix='')
>>> print(f.as_div())
<div><label for="id_for_subject">Subject</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>
>>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->')
>>> print(f.as_div())
<div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message -></label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender -></label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself -></label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>
Обратите внимание, что суффикс метки добавляется только в том случае, если последний символ метки не является знаком препинания (в английском языке это .
, !
, ?
или :
).
Fields can also define their own label_suffix
.
This will take precedence over Form.label_suffix
. The suffix can also be overridden at runtime
using the label_suffix
parameter to
label_tag()
/
legend_tag()
.
-
Form.
use_required_attribute
¶
Если установлено значение True
(по умолчанию), обязательные поля формы будут иметь HTML-атрибут required
.
Formsets инстанцируйте формы с помощью use_required_attribute=False
, чтобы избежать неправильной валидации браузера при добавлении и удалении форм из набора форм.
Настройка отображения виджетов формы¶
-
Form.
default_renderer
¶
Определяет renderer, который будет использоваться для формы. По умолчанию установлено значение None
, что означает использование рендеринга по умолчанию, заданного параметром FORM_RENDERER
.
Вы можете задать это как атрибут класса при объявлении формы или использовать аргумент renderer
для Form.__init__()
. Например:
from django import forms
class MyForm(forms.Form):
default_renderer = MyRenderer()
или:
form = MyForm(renderer=MyRenderer())
Примечания по заказу полевых работ¶
В ярлыках as_p()
, as_ul()
и as_table()
поля отображаются в том порядке, в котором вы определили их в классе формы. Например, в примере ContactForm
поля определены в порядке subject
, message
, sender
, cc_myself
. Чтобы изменить порядок вывода HTML, измените порядок, в котором эти поля перечислены в классе.
Существует еще несколько способов индивидуализации заказа:
-
Form.
field_order
¶
По умолчанию Form.field_order=None
, что сохраняет порядок, в котором вы определили поля в классе формы. Если field_order
является списком имен полей, то поля упорядочиваются так, как указано в списке, а оставшиеся поля добавляются в соответствии с порядком по умолчанию. Неизвестные имена полей в списке игнорируются. Это позволяет отключить поле в подклассе, установив его в None
без необходимости переопределять порядок.
Вы также можете использовать аргумент Form.field_order
в Form
для переопределения порядка полей. Если Form
определяет field_order
и вы включаете field_order
при инстанцировании Form
, то последний field_order
будет иметь приоритет.
-
Form.
order_fields
(field_order)¶
Вы можете переставлять поля в любое время, используя order_fields()
со списком имен полей, как в field_order
.
Как отображаются ошибки¶
Если вы выводите связанный объект Form
, то при выводе автоматически выполняется валидация формы, если она еще не выполнена, и в HTML-вывод включаются ошибки валидации в виде <ul class="errorlist">
рядом с полем. Конкретное расположение сообщений об ошибках зависит от используемого метода вывода:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid email address',
... 'cc_myself': True}
>>> f = ContactForm(data, auto_id=False)
>>> print(f.as_div())
<div>Subject:<ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required>Hi there</textarea></div>
<div>Sender:<ul class="errorlist"><li>Enter a valid email address.</li></ul><input type="email" name="sender" value="invalid email address" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself" checked></div>
>>> print(f.as_table())
<tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" required></td></tr>
<tr><th>Message:</th><td><textarea name="message" cols="40" rows="10" required></textarea></td></tr>
<tr><th>Sender:</th><td><ul class="errorlist"><li>Enter a valid email address.</li></ul><input type="email" name="sender" value="invalid email address" required></td></tr>
<tr><th>Cc myself:</th><td><input checked type="checkbox" name="cc_myself"></td></tr>
>>> print(f.as_ul())
<li><ul class="errorlist"><li>This field is required.</li></ul>Subject: <input type="text" name="subject" maxlength="100" required></li>
<li>Message: <textarea name="message" cols="40" rows="10" required></textarea></li>
<li><ul class="errorlist"><li>Enter a valid email address.</li></ul>Sender: <input type="email" name="sender" value="invalid email address" required></li>
<li>Cc myself: <input checked type="checkbox" name="cc_myself"></li>
>>> print(f.as_p())
<p><ul class="errorlist"><li>This field is required.</li></ul></p>
<p>Subject: <input type="text" name="subject" maxlength="100" required></p>
<p>Message: <textarea name="message" cols="40" rows="10" required></textarea></p>
<p><ul class="errorlist"><li>Enter a valid email address.</li></ul></p>
<p>Sender: <input type="email" name="sender" value="invalid email address" required></p>
<p>Cc myself: <input checked type="checkbox" name="cc_myself"></p>
Настройка формата списка ошибок¶
-
class
ErrorList
(initlist=None, error_class=None, renderer=None)¶ By default, forms use
django.forms.utils.ErrorList
to format validation errors.ErrorList
is a list like object whereinitlist
is the list of errors. In addition this class has the following attributes and methods.-
error_class
¶ Классы CSS, которые будут использоваться при отображении списка ошибок. Любые предоставленные классы добавляются к классу по умолчанию
errorlist
.
-
renderer
¶ Specifies the renderer to use for
ErrorList
. Defaults toNone
which means to use the default renderer specified by theFORM_RENDERER
setting.
-
template_name
¶ Имя шаблона, используемого при вызове
__str__
илиrender()
. По умолчанию это'django/forms/errors/list/default.html'
, который является прокси для шаблона'ul.html'
.
-
template_name_text
¶ Имя шаблона, используемого при вызове
as_text()
. По умолчанию это'django/forms/errors/list/text.html'
. Этот шаблон отображает ошибки в виде списка пунктов.
-
template_name_ul
¶ Имя шаблона, используемого при вызове
as_ul()
. По умолчанию это'django/forms/errors/list/ul.html'
. Этот шаблон отображает ошибки в тегах<li>
с оберткой<ul>
с классами CSS, определеннымиerror_class
.
-
get_context
()¶ Возвращает контекст для отображения ошибок в шаблоне.
Доступный контекст:
errors
: Список ошибок.error_class
: Строка классов CSS.
-
render
(template_name=None, context=None, renderer=None)¶ Метод render вызывается как методом
__str__
, так и методомas_ul()
.Все аргументы являются необязательными и будут использоваться по умолчанию:
template_name
: Значение, возвращаемоеtemplate_name
context
: Значение, возвращаемоеget_context()
renderer
: Значение, возвращаемоеrenderer
-
as_text
()¶ Выводит список ошибок, используя шаблон, определенный
template_name_text
.
-
as_ul
()¶ Выводит список ошибок, используя шаблон, определенный
template_name_ul
.
Если вы хотите настроить отображение ошибок, это можно сделать, переопределив атрибут
template_name
или, в более общем случае, переопределив шаблон по умолчанию, см. также Overriding built-in form templates.-
Не рекомендуется, начиная с версии 4.0: Возможность возвращать str
при вызове метода __str__
устарела. Вместо этого используйте шаблонизатор, который возвращает SafeString
.
Более детальный вывод¶
Методы as_p()
, as_ul()
и as_table()
являются ярлыками - это не единственный способ отображения объекта формы.
-
class
BoundField
[исходный код]¶ Используется для отображения HTML или атрибутов доступа для одного поля экземпляра
Form
.Метод
__str__()
этого объекта отображает HTML для данного поля.
Чтобы получить одно BoundField
, используйте синтаксис поиска по словарю в вашей форме, используя имя поля в качестве ключа:
>>> form = ContactForm()
>>> print(form['subject'])
<input id="id_subject" type="text" name="subject" maxlength="100" required>
Чтобы получить все объекты BoundField
, выполните итерацию формы:
>>> form = ContactForm()
>>> for boundfield in form: print(boundfield)
<input id="id_subject" type="text" name="subject" maxlength="100" required>
<input type="text" name="message" id="id_message" required>
<input type="email" name="sender" id="id_sender" required>
<input type="checkbox" name="cc_myself" id="id_cc_myself">
Вывод для конкретного поля соответствует настройке auto_id
объекта формы:
>>> f = ContactForm(auto_id=False)
>>> print(f['message'])
<input type="text" name="message" required>
>>> f = ContactForm(auto_id='id_%s')
>>> print(f['message'])
<input type="text" name="message" id="id_message" required>
Атрибуты BoundField
¶
-
BoundField.
auto_id
¶ Атрибут HTML ID для данного
BoundField
. Возвращает пустую строку, еслиForm.auto_id
являетсяFalse
.
-
BoundField.
data
¶ Это свойство возвращает данные для этого
BoundField
, извлеченные методомvalue_from_datadict()
виджета, илиNone
, если они не были переданы:>>> unbound_form = ContactForm() >>> print(unbound_form['subject'].data) None >>> bound_form = ContactForm(data={'subject': 'My Subject'}) >>> print(bound_form['subject'].data) My Subject
-
BoundField.
errors
¶ list-like object, который при печати отображается как 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.
html_name
¶ Имя, которое будет использоваться в HTML атрибуте виджета
name
. При этом учитывается формаprefix
.
-
BoundField.
id_for_label
¶ Use this property to render the ID of this field. For example, if you are manually constructing a
<label>
in your template (despite the fact thatlabel_tag()
/legend_tag()
will do this for you):<label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}
По умолчанию это будет имя поля с префиксом
id_
(»id_my_field
» для примера выше). Вы можете изменить ID, установивattrs
в виджете поля. Например, объявив поле следующим образом:my_field = forms.CharField(widget=forms.TextInput(attrs={'id': 'myFIELD'}))
и, используя вышеприведенный шаблон, можно получить что-то вроде:
<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" required>
-
BoundField.
initial
¶ Use
BoundField.initial
to retrieve initial data for a form field. It retrieves the data fromForm.initial
if present, otherwise tryingField.initial
. Callable values are evaluated. See Initial form values for more examples.BoundField.initial
кэширует свое возвращаемое значение, что особенно полезно при работе с callables, возвращаемые значения которых могут изменяться (например,datetime.now
илиuuid.uuid4
):>>> from datetime import datetime >>> class DatedCommentForm(CommentForm): ... created = forms.DateTimeField(initial=datetime.now) >>> f = DatedCommentForm() >>> f['created'].initial datetime.datetime(2021, 7, 27, 9, 5, 54) >>> f['created'].initial datetime.datetime(2021, 7, 27, 9, 5, 54)
Рекомендуется использовать
BoundField.initial
вместоget_initial_for_field()
.
Возвращает
True
, если виджет этогоBoundField
скрыт.
-
BoundField.
label
¶ The
label
of the field. This is used inlabel_tag()
/legend_tag()
.
-
BoundField.
name
¶ Имя этого поля в форме:
>>> f = ContactForm() >>> print(f['subject'].name) subject >>> print(f['message'].name) message
-
BoundField.
use_fieldset
¶ - New in Django Development version.
Возвращает значение атрибута
use_fieldset
этого виджета BoundField.
-
BoundField.
widget_type
¶ Возвращает строчное имя класса виджета обернутого поля, с удаленными трелями
input
илиwidget
. Это может быть использовано при построении форм, где расположение зависит от типа виджета. Например:{% for field in form %} {% if field.widget_type == 'checkbox' %} # render one way {% else %} # render another way {% endif %} {% endfor %}
Методы BoundField
¶
Возвращает строку HTML для представления этого как
<input type="hidden">
.**kwargs
передаются вas_widget()
.Этот метод используется в основном для внутренних целей. Вместо него следует использовать виджет.
-
BoundField.
as_widget
(widget=None, attrs=None, only_initial=False)[исходный код]¶ Рендерит поле путем рендеринга переданного виджета, добавляя любые HTML-атрибуты, переданные как
attrs
. Если виджет не указан, то будет использован виджет поля по умолчанию.only_initial
используется внутренними модулями Django и не должен быть установлен явно.
-
BoundField.
css_classes
(extra_classes=None)[исходный код]¶ Когда вы используете ярлыки рендеринга Django, CSS-классы используются для обозначения обязательных полей формы или полей, содержащих ошибки. Если вы вручную отрисовываете форму, вы можете получить доступ к этим CSS-классам, используя метод
css_classes
:>>> f = ContactForm(data={'message': ''}) >>> f['message'].css_classes() 'required'
Если вы хотите предоставить некоторые дополнительные классы в дополнение к классам error и required, которые могут потребоваться, вы можете предоставить эти классы в качестве аргумента:
>>> f = ContactForm(data={'message': ''}) >>> f['message'].css_classes('foo bar') 'foo bar required'
-
BoundField.
label_tag
(contents=None, attrs=None, label_suffix=None, tag=None)[исходный код]¶ Отображает тег label для поля формы, используя шаблон, указанный
Form.template_name_label
.Доступный контекст:
field
: Этот экземплярBoundField
.contents
: По умолчанию конкатенированная строка изBoundField.label
иForm.label_suffix
(илиField.label_suffix
, если задано). Это можно переопределить аргументамиcontents
иlabel_suffix
.attrs
:dict
, содержащийfor
,Form.required_css_class
иid
.id
генерируется виджетом поляattrs
илиBoundField.auto_id
. Дополнительные атрибуты могут быть предоставлены аргументомattrs
.use_tag
: A boolean which isTrue
if the label has anid
. IfFalse
the default template omits thetag
.tag
: Необязательная строка для настройки тега, по умолчаниюlabel
.
Совет
В вашем шаблоне
field
является экземпляромBoundField
. Поэтомуfield.field
обращается кBoundField.field
, будучи полем, которое вы объявили, например,forms.CharField
.Чтобы отдельно отобразить тег label поля формы, можно вызвать его метод
label_tag()
:>>> f = ContactForm(data={'message': ''}) >>> print(f['message'].label_tag()) <label for="id_message">Message:</label>
Если вы хотите настроить рендеринг, это можно сделать, переопределив атрибут
Form.template_name_label
или, в более общем случае, переопределив шаблон по умолчанию, см. также Overriding built-in form templates.Changed in Django Development version:Был добавлен аргумент
tag
.
-
BoundField.
legend_tag
(contents=None, attrs=None, label_suffix=None)¶ - New in Django Development version.
Вызывает
label_tag()
сtag='legend'
для рендеринга метки с тегами<legend>
. Это полезно при рендеринге виджетов радио и нескольких флажков, где<legend>
может быть более уместным, чем<label>
.
-
BoundField.
value
()[исходный код]¶ Используйте этот метод для отображения необработанного значения этого поля так, как оно было бы отображено с помощью
Widget
:>>> initial = {'subject': 'welcome'} >>> unbound_form = ContactForm(initial=initial) >>> bound_form = ContactForm(data={'subject': 'hi'}, initial=initial) >>> print(unbound_form['subject'].value()) welcome >>> print(bound_form['subject'].value()) hi
Настройка BoundField
¶
Если вам необходимо получить доступ к дополнительной информации о поле формы в шаблоне и использование подкласса Field
недостаточно, рассмотрите также возможность настройки BoundField
.
Поле пользовательской формы может переопределять get_bound_field()
:
-
Field.
get_bound_field
(form, field_name)[исходный код]¶ Принимает экземпляр
Form
и имя поля. Возвращаемое значение будет использоваться при обращении к полю в шаблоне. Скорее всего, это будет экземпляр подклассаBoundField
.
Если у вас есть, например, GPSCoordinatesField
и вы хотите иметь возможность доступа к дополнительной информации о координатах в шаблоне, это можно реализовать следующим образом:
class GPSCoordinatesBoundField(BoundField):
@property
def country(self):
"""
Return the country the coordinates lie in or None if it can't be
determined.
"""
value = self.value()
if value:
return get_country_from_coordinates(value)
else:
return None
class GPSCoordinatesField(Field):
def get_bound_field(self, form, field_name):
return GPSCoordinatesBoundField(form, self, field_name)
Теперь вы можете получить доступ к стране в шаблоне с помощью {{ form.coordinates.country }}
.
Привязка загруженных файлов к форме¶
Работа с формами, имеющими поля FileField
и ImageField
, немного сложнее, чем с обычной формой.
Во-первых, чтобы загрузить файлы, вам нужно убедиться, что ваш элемент <form>
правильно определяет enctype
как "multipart/form-data"
:
<form enctype="multipart/form-data" method="post" action="/foo/">
Во-вторых, когда вы используете форму, вам необходимо связать данные файла. Файловые данные обрабатываются отдельно от обычных данных формы, поэтому, если ваша форма содержит FileField
и ImageField
, вам необходимо указать второй аргумент при привязке формы. Таким образом, если мы расширим нашу ContactForm и добавим в нее ImageField
, называемую mugshot
, нам нужно будет связать данные файла, содержащего изображение кружки:
# Bound form with an image field
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', <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_div())
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
<div>Message:<textarea name="message" cols="40" rows="10" required></textarea></div>
<div>Sender:<input type="email" name="sender" required></div>
<div>Cc myself:<input type="checkbox" name="cc_myself"></div>
<div>Priority:<input type="text" name="priority" required></div>
Можно подклассифицировать несколько форм, рассматривая формы как миксины. В этом примере BeatleForm
является подклассом PersonForm
и InstrumentForm
(в таком порядке), и его список полей включает поля из родительских классов:
>>> from django import forms
>>> class PersonForm(forms.Form):
... first_name = forms.CharField()
... last_name = forms.CharField()
>>> class InstrumentForm(forms.Form):
... instrument = forms.CharField()
>>> class BeatleForm(InstrumentForm, PersonForm):
... haircut_type = forms.CharField()
>>> b = BeatleForm(auto_id=False)
>>> print(b.as_div())
<div>First name:<input type="text" name="first_name" required></div>
<div>Last name:<input type="text" name="last_name" required></div>
<div>Instrument:<input type="text" name="instrument" required></div>
<div>Haircut type:<input type="text" name="haircut_type" required></div>
Можно декларативно удалить Field
, унаследованное от родительского класса, установив имя поля None
в подклассе. Например:
>>> from django import forms
>>> class ParentForm(forms.Form):
... name = forms.CharField()
... age = forms.IntegerField()
>>> class ChildForm(ParentForm):
... name = None
>>> list(ChildForm().fields)
['age']
Префиксы для форм¶
-
Form.
prefix
¶
Вы можете разместить несколько форм Django внутри одного тега <form>
. Чтобы дать каждой Form
свое собственное пространство имен, используйте аргумент prefix
ключевое слово:
>>> mother = PersonForm(prefix="mother")
>>> father = PersonForm(prefix="father")
>>> print(mother.as_div())
<div><label for="id_mother-first_name">First name:</label><input type="text" name="mother-first_name" required id="id_mother-first_name"></div>
<div><label for="id_mother-last_name">Last name:</label><input type="text" name="mother-last_name" required id="id_mother-last_name"></div>
>>> print(father.as_div())
<div><label for="id_father-first_name">First name:</label><input type="text" name="father-first_name" required id="id_father-first_name"></div>
<div><label for="id_father-last_name">Last name:</label><input type="text" name="father-last_name" required id="id_father-last_name"></div>
Префикс также может быть указан на форме class:
>>> class PersonForm(forms.Form):
... ...
... prefix = 'person'