Об этом документе
Этот документ знакомит с деталями API форм Django. Сначала вы должны прочитать введение в использование форм.
Экземпляр класса Form может быть заполнен набором данных или не заполнен.
Если он заполнен, то у него есть возможность валидации полученных данных и генерации заполненной формы в виде HTML кода.
Если он не заполнен, то выполнить валидацию невозможно (так как нет для этого данных!), но есть возможность сгенерировать HTML код пустой формы.
Для создания незаполненного экземпляра Form, просто создайте объект:
>>> f = ContactForm()
Для привязки данных к форме, передайте данные в виде словаря в качестве первого параметра конструктора класса Form:
>>> data = {'subject': 'hello',
... 'message': 'Hi there',
... 'sender': 'foo@example.com',
... 'cc_myself': True}
>>> f = ContactForm(data)
В этом словаре, ключами являются имена полей, которые соответствуют атрибутам в вашем классе Form. Значения словаря являются данными, которые вам требуется проверить. Обычно значения представлены строками, но это требование не является обязательным. Тип переданных данных зависит от класса Field, это мы сейчас рассмотрим.
Если вам требуется определять заполненность экземпляров форм во время работы программы, обратитесь к значению атрибута формы 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, его данные следует рассматривать как неизменные, независимо от его заполненности.
Добавьте метод clean() в вашу форму Form, если необходимо проверить независимые поля вместе. Смотрите Очистка и проверка полей, которые зависят друг от друга.
Главной задачей объекта 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
Обратитесь к атрибуту errors для получения словаря с сообщениями об ошибках:
>>> f.errors
{'sender': ['Enter a valid email address.'], 'subject': ['This field is required.']}
В этом словаре, ключами являются имена полей, а значениями – списки юникодных строк, представляющих сообщения об ошибках. Сообщения хранятся в виде списков, так как поле может иметь множество таких сообщений.
Обращаться к атрибуту errors можно без предварительного вызова методе call is_valid(). Данные формы будут проверены при вызове метода is_valid() или при обращении к errors.
Процедуры проверки выполняются один раз, независимо от количества обращений к атрибуту errors или вызова метода is_valid(). Это означает, что если проверка данных имеет побочное влияние на состояние формы, то оно проявится только один раз.
Возвращает 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.
Возвращает ошибки в 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 запросы для отправки формы, и показываете ошибки на странице, вам следует экранировать результат на клиенте, чтобы избежать XSS атак. Это просто сделать, используя JavaScript библиотеку, например, jQuery – просто используйте $(el).text(errorText) вместо .html().
Если вы не хотите использовать экранирование на стороне клиента, можете передать аргумент escape_html=True и все ошибки будет экранированы, теперь их можно вставлять непосредственно в HTML.
Этот метод позволяет добавить ошибки конкретному полю в методе Form.clean(), или вне формы. Например, из представления.
Аргумент field указывает поле, для которого необходимо добавить ошибку. Если равен None, ошибка будет добавлена к общим ошибкам формы, которые можно получить через метод Form.non_field_errors().
Аргумент error может быть просто строкой, но лучше передавать объект ValidationError. Смотрите Вызов ValidationError.
Обратите внимание, Form.add_error() автоматически удалит поле из cleaned_data.
Этот метод возвращает True, если поле содержит ошибку с кодом code. Если code равен None, вернет True, если поле содержит любую ошибку.
Чтобы проверить наличие ошибок, которые не относятся ни к одному из полей, передайте NON_FIELD_ERRORS в параметре field.
Этот метод возвращает список ошибок из Form.errors, которые не привязаны к конкретному полю. Сюда входят ошибки ValidationError, вызванные в Form.clean(), и ошибки, добавленные через Form.add_error(None, "...").
Бессмысленно проводить проверку незаполненной формы, но покажем, что происходит с такой формой:
>>> f = ContactForm()
>>> f.is_valid()
False
>>> f.errors
{}
Используйте атрибут 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" /></td></tr>
<tr><th>Url:</th><td><input type="url" name="url" /></td></tr>
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
Используйте метод has_changed(), если необходимо проверить были ли изначальные данные изменены.
>>> 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, используя атрибут 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>
Вы можете изменить поле:
>>> f.as_table().split('\n')[0]
'<tr><th>Name:</th><td><input name="name" type="text" value="instance" /></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" /></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" /></td></tr>'
Каждое поле в классе Form отвечает не только за проверку, но и за нормализацию данных. Это приятная особенность, так как она позволяет вводить данные в определённые поля различными способами, всегда получая правильный результат.
Например, класс DateField нормализует введённое значение к объекту 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.forms import Form
>>> class OptionalPersonForm(Form):
... first_name = CharField()
... last_name = CharField()
... nick_name = CharField(required=False)
>>> data = {'first_name': 'John', 'last_name': 'Lennon'}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
>>> f.cleaned_data
{'nick_name': '', 'first_name': 'John', 'last_name': 'Lennon'}
В приведённом выше примере, значением атрибута cleaned_data для поля nick_name является пустая строка, так как nick_name – это CharField, а CharField рассматривает пустые значения как пустые строки. Каждый тип поля знает, что такое “пустое” значение, т.е. для DateField – это None, на не пустая строка. Для получения подробностей о поведении каждого типа поля обращайте внимание на заметку “Пустое значение” для каждого поля в разделе “Встроенные поля”, которые приведён далее.
Вы можете написать код для выполнения проверки определённых полей формы (используя их имена) или для проверки всей формы (рассматривая её как комбинацию полей). Подробная информация изложена в Проверка форм и полей формы.
Второй задачей объекта Form является представление себя в виде HTML кода. Для этого объект надо просто “распечатать”:
>>> f = ContactForm()
>>> print(f)
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></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="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" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" value="Hi there" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" value="foo@example.com" /></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="checked" /></td></tr>
По умолчанию в HTML форма представляется в виде таблицы, т.е. каждое поле обёрнуто в <tr>. Обратите внимание на:
Для гибкости, выводимый код не включает в себя ни теги <table> и </table>, ни теги <form> and </form>, ни тег <input type="submit">. Не забывайте их добавлять.
Каждый тип поля имеет стандартное HTML представление. Тип CharField``представлен как ``<input type="text">, а EmailField как <input type="email">. Тип BooleanField представлен <input type="checkbox">. Следует отметить, что эти представления достаточно гибкие, так как вы можете влиять на них, указав для поля виджет. Далее мы покажем как это делается.
Атрибут name каждого тега совпадает напрямую с именем атрибута в классе ContactForm.
Текстовая метка каждого поля, т.е. 'Subject:', 'Message:' и 'Cc myself:', генерируется из имени поля, конвертируя символы подчёркивания в пробелы и переводя первый символ в верхний регистр. Также, вы можете явно назначить текстовую метку для поля.
Каждая текстовая метка выводится с помощью тега <label>, который указывает на соответствующее поле формы с помощью атрибута id. Атрибут id генерируется путём добавления префикса 'id_' к имени поля. Атрибуты id и теги <label> включаются в HTML представление формы по умолчанию, но можете изменить такое поведение формы.
Несмотря на то, что по умолчанию форма выводится в табличном виде, существует ряд других представлений. Каждое представление доступно через метод объекта формы, возвращая объект Unicode.
Метод as_p() представляет форму в виде последовательности тегов <p>, по одному на каждое поле:
>>> f = ContactForm()
>>> f.as_p()
'<p><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></p>\n<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>\n<p><label for="id_sender">Sender:</label> <input type="text" name="sender" id="id_sender" /></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" /></p>
<p><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></p>
<p><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></p>
<p><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p>
Метод as_ul() представляет форму в виде последовательности тегов <li>, по одному на каждое поле. Представление не включает в себя теги <ul> или </ul>, таким образом вы можете указать любой атрибут для тега <ul>:
>>> f = ContactForm()
>>> f.as_ul()
'<li><label for="id_subject">Subject:</label> <input id="id_subject" type="text" name="subject" maxlength="100" /></li>\n<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>\n<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></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" /></li>
<li><label for="id_message">Message:</label> <input type="text" name="message" id="id_message" /></li>
<li><label for="id_sender">Sender:</label> <input type="email" name="sender" id="id_sender" /></li>
<li><label for="id_cc_myself">Cc myself:</label> <input type="checkbox" name="cc_myself" id="id_cc_myself" /></li>
Наконец, метод 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" /></td></tr>\n<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>\n<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></td></tr>\n<tr><th><label for="id_cc_myself">Cc myself:</label></th><td><input type="checkbox" name="cc_myself" id="id_cc_myself" /></td></tr>'
>>> print(f.as_table())
<tr><th><label for="id_subject">Subject:</label></th><td><input id="id_subject" type="text" name="subject" maxlength="100" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>
<tr><th><label for="id_sender">Sender:</label></th><td><input type="email" name="sender" id="id_sender" /></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 имеет ряд возможностей, которые вы можете использовать для добавления атрибутов class к обязательным полям и полям с ошибками: просто определите атрибут Form.error_css_class и/или Form.required_css_class attributes:
from django.forms import Form
class ContactForm(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>
required_css_class будет также добавлен к тегу <label>, как это показано выше.
По умолчанию методы для рендеринга форма включают:
HTML атрибуты id элементов формы.
Тег <label> определяет, с каким элементом формы связана текущая текстовая метка. Это небольшое уточнение делает форму более открытой для устройств. Советуем использовать теги <label>.
Атрибуты id создаются с помощью добавления префикса id_ к именам полей формы. Это поведение является изменяемым, таким образом вы можете изменить его или вообще удалить эти атрибуты и тег <label> из формы.
Используйте аргумент auto_id конструктора Form для управления поведением меток и их идентификаторов. Этот аргумент может принимать значения 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" /></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" /></td></tr>
<tr><th>Sender:</th><td><input type="email" name="sender" /></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" /></li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="email" name="sender" /></li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
>>> print(f.as_p())
<p>Subject: <input type="text" name="subject" maxlength="100" /></p>
<p>Message: <input type="text" name="message" /></p>
<p>Sender: <input type="email" name="sender" /></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" /></td></tr>
<tr><th><label for="message">Message:</label></th><td><input type="text" name="message" id="message" /></td></tr>
<tr><th><label for="sender">Sender:</label></th><td><input type="email" name="sender" id="sender" /></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" /></li>
<li><label for="message">Message:</label> <input type="text" name="message" id="message" /></li>
<li><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" /></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" /></p>
<p><label for="message">Message:</label> <input type="text" name="message" id="message" /></p>
<p><label for="sender">Sender:</label> <input type="email" name="sender" id="sender" /></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" /></td></tr>
<tr><th><label for="id_for_message">Message:</label></th><td><input type="text" name="message" id="id_for_message" /></td></tr>
<tr><th><label for="id_for_sender">Sender:</label></th><td><input type="email" name="sender" id="id_for_sender" /></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" /></li>
<li><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" /></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" /></p>
<p><label for="id_for_message">Message:</label> <input type="text" name="message" id="id_for_message" /></p>
<p><label for="id_for_sender">Sender:</label> <input type="email" name="sender" id="id_for_sender" /></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 равно любому другому значимому значению (например, строка, которая не содержит символа форматирования), тогда библиотека будет рассматривать это значение как True.
По умолчанию, auto_id имеет значение 'id_%s'.
Строка(по умолчанию двоеточие (:)), которая будет добавлена к названию метки поля. Строка локализирована и можно перевести на разные языки.
Есть возможность заменить это двоеточие на другой символ или вообще убрать его. Для этого надо воспользоваться параметром 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" /></li>
<li><label for="id_for_message">Message</label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender</label> <input type="email" name="sender" id="id_for_sender" /></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" /></li>
<li><label for="id_for_message">Message -></label> <input type="text" name="message" id="id_for_message" /></li>
<li><label for="id_for_sender">Sender -></label> <input type="email" name="sender" id="id_for_sender" /></li>
<li><label for="id_for_cc_myself">Cc myself -></label> <input type="checkbox" name="cc_myself" id="id_for_cc_myself" /></li>
Следует отметить, что суффикс добавляется к метке только в том случае, когда последний символ метки не является пунктуационным, т.е. не принадлежит списку (., !, ? or :).
Поля могут также могут указывать свои label_suffix. У этого значение приоритет выше, чем у Form.label_suffix. Этот суфикс может быть переопределен во время выполнения через параметр label_suffix атрибута label_tag().
При использовании методов as_p(), as_ul() и as_table() поля отображаются в порядке их определения в классе формы. Например, в нашей форме ContactForm поля определены в порядке subject, message, sender, cc_myself. Для изменения их порядка на форме, просто поменяйте их местами в классе.
При отображении заполненного объекта Form, процесс генерации HTML кода автоматически выполняет проверку данных формы, если она ещё не была произведена. Если проверка выявила ошибки, то HTML код формы будет включать в себя список ошибок в виде списка <ul class="errorlist"> у соответствующего поля. Точная позиция списка сообщений с ошибками проверки зависит от метода, который вы используете:
>>> data = {'subject': '',
... 'message': 'Hi there',
... 'sender': 'invalid email address',
... 'cc_myself': True}
>>> f = ContactForm(data, auto_id=False)
>>> print(f.as_table())
<tr><th>Subject:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" /></td></tr>
<tr><th>Message:</th><td><input type="text" name="message" value="Hi there" /></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" /></td></tr>
<tr><th>Cc myself:</th><td><input checked="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" /></li>
<li>Message: <input type="text" name="message" value="Hi there" /></li>
<li><ul class="errorlist"><li>Enter a valid email address.</li></ul>Sender: <input type="email" name="sender" value="invalid email address" /></li>
<li>Cc myself: <input checked="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" /></p>
<p>Message: <input type="text" name="message" value="Hi there" /></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" /></p>
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
По умолчанию, формы используют django.forms.utils.ErrorList для форматирования списка с ошибками . Если вам требуется использовать другой класс для отображения ошибок, вы можете передать его во время создания объекта формы (замените __str__ на __unicode__ для Python 2):
>>> from django.forms.utils import ErrorList
>>> class DivErrorList(ErrorList):
... def __str__(self): # __unicode__ on Python 2
... 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" /></p>
<p>Message: <input type="text" name="message" value="Hi there" /></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" /></p>
<p>Cc myself: <input checked="checked" type="checkbox" name="cc_myself" /></p>
django.forms.util был переименован в django.forms.utils.
Методы as_p(), as_ul() и as_table() являются общими методами для ленивых разработчиков. Это не единственные способы отображения формы.
Используется для отображения HTML или для доступа к атрибутам отдельного поля экземпляра Form.
Метод __str__() (__unicode__ в Python 2) этого объекта возвращают HTML для данного поля.
Для получение одного BoundField используйте синтаксис поиска в словаре, применяя имя поля в качестве ключа:
>>> form = ContactForm()
>>> print(form['subject'])
<input id="id_subject" type="text" name="subject" maxlength="100" />
Для получения всех объектов BoundField, пройдите циклом по форме:
>>> form = ContactForm()
>>> for boundfield in form: print(boundfield)
<input id="id_subject" type="text" name="subject" maxlength="100" />
<input type="text" name="message" id="id_message" />
<input type="email" name="sender" id="id_sender" />
<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" />
>>> f = ContactForm(auto_id='id_%s')
>>> print(f['message'])
<input type="text" name="message" id="id_message" />
Для получения списка ошибок в полях формы следует использовать атрибут errors.
Объект со свойствами списка, который при отображении представляется в виде <ul class="errorlist">:
>>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
>>> f = ContactForm(data, auto_id=False)
>>> print(f['message'])
<input type="text" name="message" />
>>> 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)
''
Чтобы отдельно отрендерить label поля, вызовите метод label_tag:
>>> f = ContactForm(data)
>>> print(f['message'].label_tag())
<label for="id_message">Message:</label>
Вы можете передать параметр contents, который заменит автоматически генерируемый тег. Необязательный параметр attrs, который является словарем, может передавать дополнительные атрибуты для тега <label>.
Сгенерированный HTML содержит label_suffix формы (двоеточие по умолчанию), или label_suffix поля, если этот атрибут установлен. Необязательный аргумент label_suffix позволяет переопределить установленный ранее суфикс. Например, можно использовать пустую строку, чтобы скрыть метку поля. Если это необходимо сделать в шаблоне, создайте собственный фильтр, который позволяет передавать значение в label_tag.
Метка поля содержит required_css_class, если поле обязательно.
Когда вы применяете общие методы для отображения формы, для выделения обязательных полей формы или полей, которые содержат ошибки, используются CSS классы. Если вы вручную выводите форму, вы можете получить доступ к этим классам через метод css_classes:
>>> f = ContactForm(data)
>>> f['message'].css_classes()
'required'
Если потребуется предоставить дополнительные классы для ошибок и обязательных полей, вы можете указать эти классы в качестве аргумента:
>>> f = ContactForm(data)
>>> f['message'].css_classes('foo bar')
'foo bar required'
Используйте этот метод для выдачи “сырого” значения данного поля, как будто бы оно было отображено через Widget:
>>> initial = {'subject': 'welcome'}
>>> unbound_form = ContactForm(initial=initial)
>>> bound_form = ContactForm(data, initial=initial)
>>> print(unbound_form['subject'].value())
welcome
>>> print(bound_form['subject'].value())
hi
Этот атрибут рендерит ID поля. Например, вы можете использовать его, если вы самостоятельно создаете <label> для поля (несмотря на то, что label_tag() делает это для вас):
<label for="{{ form.my_field.id_for_label }}">...</label>{{ my_field }}
По умолчанию, он равен названию поля с префиксом id_ (“id_my_field” для примера выше). Вы можете изменить ID, передав его в параметре attrs виджета. Например, определив поле следующим образом:
my_field = forms.CharField(widget=forms.TextInput(attrs={'id': 'myFIELD'}))
и используя пример выше, получите следующий результат:
<label for="myFIELD">...</label><input id="myFIELD" type="text" name="my_field" />
Работа с формами, которые содержат поля FileField и ImageField немного отличается от работы с обычными формами.
Сначала, для того, чтобы загружать файлы, вам потребуется назначить форме атрибут enctype:
<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()
Если вы пишете представления и шаблоны в расчёте на их неоднократное использование в будущем, вы не можете знать, будет ли ваша форма обычной или будет работать с файлами. В этом случае вам поможет метод 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" /></li>
<li>Message: <input type="text" name="message" /></li>
<li>Sender: <input type="email" name="sender" /></li>
<li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
<li>Priority: <input type="text" name="priority" /></li>
Так же можно наследовать несколько форм, рассматривая формы как “смесь”. В этом примере форма BeatleForm наследует формы PersonForm и InstrumentForm (именно в этом порядке) и её список полей включает в себя поля из родительских классов:
>>> from django.forms import Form
>>> class PersonForm(Form):
... first_name = CharField()
... last_name = CharField()
>>> class InstrumentForm(Form):
... instrument = CharField()
>>> class BeatleForm(PersonForm, InstrumentForm):
... haircut_type = CharField()
>>> b = BeatleForm(auto_id=False)
>>> print(b.as_ul())
<li>First name: <input type="text" name="first_name" /></li>
<li>Last name: <input type="text" name="last_name" /></li>
<li>Instrument: <input type="text" name="instrument" /></li>
<li>Haircut type: <input type="text" name="haircut_type" /></li>
Добавлена возможность декларативно удалить поле, унаследованное от родительского класса, указав None. Например:
>>> from django import forms
>>> class ParentForm(forms.Form):
... name = forms.CharField()
... age = forms.IntegerField()
>>> class ChildForm(ParentForm):
... name = None
>>> ChildForm().fields.keys()
... ['age']
Вы можете размещать несколько форм в одном теге <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" /></li>
<li><label for="id_mother-last_name">Last name:</label> <input type="text" name="mother-last_name" id="id_mother-last_name" /></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" /></li>
<li><label for="id_father-last_name">Last name:</label> <input type="text" name="father-last_name" id="id_father-last_name" /></li>
Jun 02, 2016