PageRenderTime 68ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/tests/forms_tests/tests/test_forms.py

https://gitlab.com/mayakarya/django
Python | 1039 lines | 998 code | 20 blank | 21 comment | 10 complexity | 43216d0b7716c4303e1b283ceb7a9d7b MD5 | raw file
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import copy
  4. import datetime
  5. import json
  6. import uuid
  7. from django.core.exceptions import NON_FIELD_ERRORS
  8. from django.core.files.uploadedfile import SimpleUploadedFile
  9. from django.core.validators import RegexValidator
  10. from django.forms import (
  11. BooleanField, CharField, CheckboxSelectMultiple, ChoiceField, DateField,
  12. DateTimeField, EmailField, FileField, FloatField, Form, HiddenInput,
  13. ImageField, IntegerField, MultipleChoiceField, MultipleHiddenInput,
  14. MultiValueField, NullBooleanField, PasswordInput, RadioSelect, Select,
  15. SplitDateTimeField, SplitHiddenDateTimeWidget, Textarea, TextInput,
  16. TimeField, ValidationError, forms,
  17. )
  18. from django.forms.utils import ErrorList
  19. from django.http import QueryDict
  20. from django.template import Context, Template
  21. from django.test import SimpleTestCase
  22. from django.test.utils import str_prefix
  23. from django.utils import six
  24. from django.utils.datastructures import MultiValueDict
  25. from django.utils.encoding import force_text, python_2_unicode_compatible
  26. from django.utils.html import format_html
  27. from django.utils.safestring import SafeData, mark_safe
  28. class Person(Form):
  29. first_name = CharField()
  30. last_name = CharField()
  31. birthday = DateField()
  32. class PersonNew(Form):
  33. first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'}))
  34. last_name = CharField()
  35. birthday = DateField()
  36. class MultiValueDictLike(dict):
  37. def getlist(self, key):
  38. return [self[key]]
  39. class FormsTestCase(SimpleTestCase):
  40. # A Form is a collection of Fields. It knows how to validate a set of data and it
  41. # knows how to render itself in a couple of default ways (e.g., an HTML table).
  42. # You can pass it data in __init__(), as a dictionary.
  43. def test_form(self):
  44. # Pass a dictionary to a Form's __init__().
  45. p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'})
  46. self.assertTrue(p.is_bound)
  47. self.assertEqual(p.errors, {})
  48. self.assertTrue(p.is_valid())
  49. self.assertHTMLEqual(p.errors.as_ul(), '')
  50. self.assertEqual(p.errors.as_text(), '')
  51. self.assertEqual(p.cleaned_data["first_name"], 'John')
  52. self.assertEqual(p.cleaned_data["last_name"], 'Lennon')
  53. self.assertEqual(p.cleaned_data["birthday"], datetime.date(1940, 10, 9))
  54. self.assertHTMLEqual(
  55. str(p['first_name']),
  56. '<input type="text" name="first_name" value="John" id="id_first_name" required />'
  57. )
  58. self.assertHTMLEqual(
  59. str(p['last_name']),
  60. '<input type="text" name="last_name" value="Lennon" id="id_last_name" required />'
  61. )
  62. self.assertHTMLEqual(
  63. str(p['birthday']),
  64. '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required />'
  65. )
  66. msg = "Key 'nonexistentfield' not found in 'Person'. Choices are: birthday, first_name, last_name."
  67. with self.assertRaisesMessage(KeyError, msg):
  68. p['nonexistentfield']
  69. form_output = []
  70. for boundfield in p:
  71. form_output.append(str(boundfield))
  72. self.assertHTMLEqual(
  73. '\n'.join(form_output),
  74. """<input type="text" name="first_name" value="John" id="id_first_name" required />
  75. <input type="text" name="last_name" value="Lennon" id="id_last_name" required />
  76. <input type="text" name="birthday" value="1940-10-9" id="id_birthday" required />"""
  77. )
  78. form_output = []
  79. for boundfield in p:
  80. form_output.append([boundfield.label, boundfield.data])
  81. self.assertEqual(form_output, [
  82. ['First name', 'John'],
  83. ['Last name', 'Lennon'],
  84. ['Birthday', '1940-10-9']
  85. ])
  86. self.assertHTMLEqual(
  87. str(p),
  88. """<tr><th><label for="id_first_name">First name:</label></th><td>
  89. <input type="text" name="first_name" value="John" id="id_first_name" required /></td></tr>
  90. <tr><th><label for="id_last_name">Last name:</label></th><td>
  91. <input type="text" name="last_name" value="Lennon" id="id_last_name" required /></td></tr>
  92. <tr><th><label for="id_birthday">Birthday:</label></th><td>
  93. <input type="text" name="birthday" value="1940-10-9" id="id_birthday" required /></td></tr>"""
  94. )
  95. def test_empty_dict(self):
  96. # Empty dictionaries are valid, too.
  97. p = Person({})
  98. self.assertTrue(p.is_bound)
  99. self.assertEqual(p.errors['first_name'], ['This field is required.'])
  100. self.assertEqual(p.errors['last_name'], ['This field is required.'])
  101. self.assertEqual(p.errors['birthday'], ['This field is required.'])
  102. self.assertFalse(p.is_valid())
  103. self.assertEqual(p.cleaned_data, {})
  104. self.assertHTMLEqual(
  105. str(p),
  106. """<tr><th><label for="id_first_name">First name:</label></th><td>
  107. <ul class="errorlist"><li>This field is required.</li></ul>
  108. <input type="text" name="first_name" id="id_first_name" required /></td></tr>
  109. <tr><th><label for="id_last_name">Last name:</label></th>
  110. <td><ul class="errorlist"><li>This field is required.</li></ul>
  111. <input type="text" name="last_name" id="id_last_name" required /></td></tr>
  112. <tr><th><label for="id_birthday">Birthday:</label></th><td>
  113. <ul class="errorlist"><li>This field is required.</li></ul>
  114. <input type="text" name="birthday" id="id_birthday" required /></td></tr>"""
  115. )
  116. self.assertHTMLEqual(
  117. p.as_table(),
  118. """<tr><th><label for="id_first_name">First name:</label></th><td>
  119. <ul class="errorlist"><li>This field is required.</li></ul>
  120. <input type="text" name="first_name" id="id_first_name" required /></td></tr>
  121. <tr><th><label for="id_last_name">Last name:</label></th>
  122. <td><ul class="errorlist"><li>This field is required.</li></ul>
  123. <input type="text" name="last_name" id="id_last_name" required /></td></tr>
  124. <tr><th><label for="id_birthday">Birthday:</label></th>
  125. <td><ul class="errorlist"><li>This field is required.</li></ul>
  126. <input type="text" name="birthday" id="id_birthday" required /></td></tr>"""
  127. )
  128. self.assertHTMLEqual(
  129. p.as_ul(),
  130. """<li><ul class="errorlist"><li>This field is required.</li></ul>
  131. <label for="id_first_name">First name:</label>
  132. <input type="text" name="first_name" id="id_first_name" required /></li>
  133. <li><ul class="errorlist"><li>This field is required.</li></ul>
  134. <label for="id_last_name">Last name:</label>
  135. <input type="text" name="last_name" id="id_last_name" required /></li>
  136. <li><ul class="errorlist"><li>This field is required.</li></ul>
  137. <label for="id_birthday">Birthday:</label>
  138. <input type="text" name="birthday" id="id_birthday" required /></li>"""
  139. )
  140. self.assertHTMLEqual(
  141. p.as_p(),
  142. """<ul class="errorlist"><li>This field is required.</li></ul>
  143. <p><label for="id_first_name">First name:</label>
  144. <input type="text" name="first_name" id="id_first_name" required /></p>
  145. <ul class="errorlist"><li>This field is required.</li></ul>
  146. <p><label for="id_last_name">Last name:</label>
  147. <input type="text" name="last_name" id="id_last_name" required /></p>
  148. <ul class="errorlist"><li>This field is required.</li></ul>
  149. <p><label for="id_birthday">Birthday:</label>
  150. <input type="text" name="birthday" id="id_birthday" required /></p>"""
  151. )
  152. def test_unbound_form(self):
  153. # If you don't pass any values to the Form's __init__(), or if you pass None,
  154. # the Form will be considered unbound and won't do any validation. Form.errors
  155. # will be an empty dictionary *but* Form.is_valid() will return False.
  156. p = Person()
  157. self.assertFalse(p.is_bound)
  158. self.assertEqual(p.errors, {})
  159. self.assertFalse(p.is_valid())
  160. with self.assertRaises(AttributeError):
  161. p.cleaned_data
  162. self.assertHTMLEqual(
  163. str(p),
  164. """<tr><th><label for="id_first_name">First name:</label></th><td>
  165. <input type="text" name="first_name" id="id_first_name" required /></td></tr>
  166. <tr><th><label for="id_last_name">Last name:</label></th><td>
  167. <input type="text" name="last_name" id="id_last_name" required /></td></tr>
  168. <tr><th><label for="id_birthday">Birthday:</label></th><td>
  169. <input type="text" name="birthday" id="id_birthday" required /></td></tr>"""
  170. )
  171. self.assertHTMLEqual(
  172. p.as_table(),
  173. """<tr><th><label for="id_first_name">First name:</label></th><td>
  174. <input type="text" name="first_name" id="id_first_name" required /></td></tr>
  175. <tr><th><label for="id_last_name">Last name:</label></th><td>
  176. <input type="text" name="last_name" id="id_last_name" required /></td></tr>
  177. <tr><th><label for="id_birthday">Birthday:</label></th><td>
  178. <input type="text" name="birthday" id="id_birthday" required /></td></tr>"""
  179. )
  180. self.assertHTMLEqual(
  181. p.as_ul(),
  182. """<li><label for="id_first_name">First name:</label>
  183. <input type="text" name="first_name" id="id_first_name" required /></li>
  184. <li><label for="id_last_name">Last name:</label>
  185. <input type="text" name="last_name" id="id_last_name" required /></li>
  186. <li><label for="id_birthday">Birthday:</label>
  187. <input type="text" name="birthday" id="id_birthday" required /></li>"""
  188. )
  189. self.assertHTMLEqual(
  190. p.as_p(),
  191. """<p><label for="id_first_name">First name:</label>
  192. <input type="text" name="first_name" id="id_first_name" required /></p>
  193. <p><label for="id_last_name">Last name:</label>
  194. <input type="text" name="last_name" id="id_last_name" required /></p>
  195. <p><label for="id_birthday">Birthday:</label>
  196. <input type="text" name="birthday" id="id_birthday" required /></p>"""
  197. )
  198. def test_unicode_values(self):
  199. # Unicode values are handled properly.
  200. p = Person({
  201. 'first_name': 'John',
  202. 'last_name': '\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111',
  203. 'birthday': '1940-10-9'
  204. })
  205. self.assertHTMLEqual(
  206. p.as_table(),
  207. '<tr><th><label for="id_first_name">First name:</label></th><td>'
  208. '<input type="text" name="first_name" value="John" id="id_first_name" required /></td></tr>\n'
  209. '<tr><th><label for="id_last_name">Last name:</label>'
  210. '</th><td><input type="text" name="last_name" '
  211. 'value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111"'
  212. 'id="id_last_name" required /></td></tr>\n'
  213. '<tr><th><label for="id_birthday">Birthday:</label></th><td>'
  214. '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required /></td></tr>'
  215. )
  216. self.assertHTMLEqual(
  217. p.as_ul(),
  218. '<li><label for="id_first_name">First name:</label> '
  219. '<input type="text" name="first_name" value="John" id="id_first_name" required /></li>\n'
  220. '<li><label for="id_last_name">Last name:</label> '
  221. '<input type="text" name="last_name" '
  222. 'value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" required /></li>\n'
  223. '<li><label for="id_birthday">Birthday:</label> '
  224. '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required /></li>'
  225. )
  226. self.assertHTMLEqual(
  227. p.as_p(),
  228. '<p><label for="id_first_name">First name:</label> '
  229. '<input type="text" name="first_name" value="John" id="id_first_name" required /></p>\n'
  230. '<p><label for="id_last_name">Last name:</label> '
  231. '<input type="text" name="last_name" '
  232. 'value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" id="id_last_name" required /></p>\n'
  233. '<p><label for="id_birthday">Birthday:</label> '
  234. '<input type="text" name="birthday" value="1940-10-9" id="id_birthday" required /></p>'
  235. )
  236. p = Person({'last_name': 'Lennon'})
  237. self.assertEqual(p.errors['first_name'], ['This field is required.'])
  238. self.assertEqual(p.errors['birthday'], ['This field is required.'])
  239. self.assertFalse(p.is_valid())
  240. self.assertDictEqual(
  241. p.errors,
  242. {'birthday': ['This field is required.'], 'first_name': ['This field is required.']}
  243. )
  244. self.assertEqual(p.cleaned_data, {'last_name': 'Lennon'})
  245. self.assertEqual(p['first_name'].errors, ['This field is required.'])
  246. self.assertHTMLEqual(
  247. p['first_name'].errors.as_ul(),
  248. '<ul class="errorlist"><li>This field is required.</li></ul>'
  249. )
  250. self.assertEqual(p['first_name'].errors.as_text(), '* This field is required.')
  251. p = Person()
  252. self.assertHTMLEqual(
  253. str(p['first_name']),
  254. '<input type="text" name="first_name" id="id_first_name" required />',
  255. )
  256. self.assertHTMLEqual(str(p['last_name']), '<input type="text" name="last_name" id="id_last_name" required />')
  257. self.assertHTMLEqual(str(p['birthday']), '<input type="text" name="birthday" id="id_birthday" required />')
  258. def test_cleaned_data_only_fields(self):
  259. # cleaned_data will always *only* contain a key for fields defined in the
  260. # Form, even if you pass extra data when you define the Form. In this
  261. # example, we pass a bunch of extra fields to the form constructor,
  262. # but cleaned_data contains only the form's fields.
  263. data = {
  264. 'first_name': 'John',
  265. 'last_name': 'Lennon',
  266. 'birthday': '1940-10-9',
  267. 'extra1': 'hello',
  268. 'extra2': 'hello',
  269. }
  270. p = Person(data)
  271. self.assertTrue(p.is_valid())
  272. self.assertEqual(p.cleaned_data['first_name'], 'John')
  273. self.assertEqual(p.cleaned_data['last_name'], 'Lennon')
  274. self.assertEqual(p.cleaned_data['birthday'], datetime.date(1940, 10, 9))
  275. def test_optional_data(self):
  276. # cleaned_data will include a key and value for *all* fields defined in the Form,
  277. # even if the Form's data didn't include a value for fields that are not
  278. # required. In this example, the data dictionary doesn't include a value for the
  279. # "nick_name" field, but cleaned_data includes it. For CharFields, it's set to the
  280. # empty string.
  281. class OptionalPersonForm(Form):
  282. first_name = CharField()
  283. last_name = CharField()
  284. nick_name = CharField(required=False)
  285. data = {'first_name': 'John', 'last_name': 'Lennon'}
  286. f = OptionalPersonForm(data)
  287. self.assertTrue(f.is_valid())
  288. self.assertEqual(f.cleaned_data['nick_name'], '')
  289. self.assertEqual(f.cleaned_data['first_name'], 'John')
  290. self.assertEqual(f.cleaned_data['last_name'], 'Lennon')
  291. # For DateFields, it's set to None.
  292. class OptionalPersonForm(Form):
  293. first_name = CharField()
  294. last_name = CharField()
  295. birth_date = DateField(required=False)
  296. data = {'first_name': 'John', 'last_name': 'Lennon'}
  297. f = OptionalPersonForm(data)
  298. self.assertTrue(f.is_valid())
  299. self.assertIsNone(f.cleaned_data['birth_date'])
  300. self.assertEqual(f.cleaned_data['first_name'], 'John')
  301. self.assertEqual(f.cleaned_data['last_name'], 'Lennon')
  302. def test_auto_id(self):
  303. # "auto_id" tells the Form to add an "id" attribute to each form element.
  304. # If it's a string that contains '%s', Django will use that as a format string
  305. # into which the field's name will be inserted. It will also put a <label> around
  306. # the human-readable labels for a field.
  307. p = Person(auto_id='%s_id')
  308. self.assertHTMLEqual(
  309. p.as_table(),
  310. """<tr><th><label for="first_name_id">First name:</label></th><td>
  311. <input type="text" name="first_name" id="first_name_id" required /></td></tr>
  312. <tr><th><label for="last_name_id">Last name:</label></th><td>
  313. <input type="text" name="last_name" id="last_name_id" required /></td></tr>
  314. <tr><th><label for="birthday_id">Birthday:</label></th><td>
  315. <input type="text" name="birthday" id="birthday_id" required /></td></tr>"""
  316. )
  317. self.assertHTMLEqual(
  318. p.as_ul(),
  319. """<li><label for="first_name_id">First name:</label>
  320. <input type="text" name="first_name" id="first_name_id" required /></li>
  321. <li><label for="last_name_id">Last name:</label>
  322. <input type="text" name="last_name" id="last_name_id" required /></li>
  323. <li><label for="birthday_id">Birthday:</label>
  324. <input type="text" name="birthday" id="birthday_id" required /></li>"""
  325. )
  326. self.assertHTMLEqual(
  327. p.as_p(),
  328. """<p><label for="first_name_id">First name:</label>
  329. <input type="text" name="first_name" id="first_name_id" required /></p>
  330. <p><label for="last_name_id">Last name:</label>
  331. <input type="text" name="last_name" id="last_name_id" required /></p>
  332. <p><label for="birthday_id">Birthday:</label>
  333. <input type="text" name="birthday" id="birthday_id" required /></p>"""
  334. )
  335. def test_auto_id_true(self):
  336. # If auto_id is any True value whose str() does not contain '%s', the "id"
  337. # attribute will be the name of the field.
  338. p = Person(auto_id=True)
  339. self.assertHTMLEqual(
  340. p.as_ul(),
  341. """<li><label for="first_name">First name:</label>
  342. <input type="text" name="first_name" id="first_name" required /></li>
  343. <li><label for="last_name">Last name:</label>
  344. <input type="text" name="last_name" id="last_name" required /></li>
  345. <li><label for="birthday">Birthday:</label>
  346. <input type="text" name="birthday" id="birthday" required /></li>"""
  347. )
  348. def test_auto_id_false(self):
  349. # If auto_id is any False value, an "id" attribute won't be output unless it
  350. # was manually entered.
  351. p = Person(auto_id=False)
  352. self.assertHTMLEqual(
  353. p.as_ul(),
  354. """<li>First name: <input type="text" name="first_name" required /></li>
  355. <li>Last name: <input type="text" name="last_name" required /></li>
  356. <li>Birthday: <input type="text" name="birthday" required /></li>"""
  357. )
  358. def test_id_on_field(self):
  359. # In this example, auto_id is False, but the "id" attribute for the "first_name"
  360. # field is given. Also note that field gets a <label>, while the others don't.
  361. p = PersonNew(auto_id=False)
  362. self.assertHTMLEqual(
  363. p.as_ul(),
  364. """<li><label for="first_name_id">First name:</label>
  365. <input type="text" id="first_name_id" name="first_name" required /></li>
  366. <li>Last name: <input type="text" name="last_name" required /></li>
  367. <li>Birthday: <input type="text" name="birthday" required /></li>"""
  368. )
  369. def test_auto_id_on_form_and_field(self):
  370. # If the "id" attribute is specified in the Form and auto_id is True, the "id"
  371. # attribute in the Form gets precedence.
  372. p = PersonNew(auto_id=True)
  373. self.assertHTMLEqual(
  374. p.as_ul(),
  375. """<li><label for="first_name_id">First name:</label>
  376. <input type="text" id="first_name_id" name="first_name" required /></li>
  377. <li><label for="last_name">Last name:</label>
  378. <input type="text" name="last_name" id="last_name" required /></li>
  379. <li><label for="birthday">Birthday:</label>
  380. <input type="text" name="birthday" id="birthday" required /></li>"""
  381. )
  382. def test_various_boolean_values(self):
  383. class SignupForm(Form):
  384. email = EmailField()
  385. get_spam = BooleanField()
  386. f = SignupForm(auto_id=False)
  387. self.assertHTMLEqual(str(f['email']), '<input type="email" name="email" required />')
  388. self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" required />')
  389. f = SignupForm({'email': 'test@example.com', 'get_spam': True}, auto_id=False)
  390. self.assertHTMLEqual(str(f['email']), '<input type="email" name="email" value="test@example.com" required />')
  391. self.assertHTMLEqual(
  392. str(f['get_spam']),
  393. '<input checked type="checkbox" name="get_spam" required />',
  394. )
  395. # 'True' or 'true' should be rendered without a value attribute
  396. f = SignupForm({'email': 'test@example.com', 'get_spam': 'True'}, auto_id=False)
  397. self.assertHTMLEqual(
  398. str(f['get_spam']),
  399. '<input checked type="checkbox" name="get_spam" required />',
  400. )
  401. f = SignupForm({'email': 'test@example.com', 'get_spam': 'true'}, auto_id=False)
  402. self.assertHTMLEqual(
  403. str(f['get_spam']), '<input checked type="checkbox" name="get_spam" required />')
  404. # A value of 'False' or 'false' should be rendered unchecked
  405. f = SignupForm({'email': 'test@example.com', 'get_spam': 'False'}, auto_id=False)
  406. self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" required />')
  407. f = SignupForm({'email': 'test@example.com', 'get_spam': 'false'}, auto_id=False)
  408. self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" required />')
  409. # A value of '0' should be interpreted as a True value (#16820)
  410. f = SignupForm({'email': 'test@example.com', 'get_spam': '0'})
  411. self.assertTrue(f.is_valid())
  412. self.assertTrue(f.cleaned_data.get('get_spam'))
  413. def test_widget_output(self):
  414. # Any Field can have a Widget class passed to its constructor:
  415. class ContactForm(Form):
  416. subject = CharField()
  417. message = CharField(widget=Textarea)
  418. f = ContactForm(auto_id=False)
  419. self.assertHTMLEqual(str(f['subject']), '<input type="text" name="subject" required />')
  420. self.assertHTMLEqual(str(f['message']), '<textarea name="message" rows="10" cols="40" required></textarea>')
  421. # as_textarea(), as_text() and as_hidden() are shortcuts for changing the output
  422. # widget type:
  423. self.assertHTMLEqual(
  424. f['subject'].as_textarea(),
  425. '<textarea name="subject" rows="10" cols="40" required></textarea>',
  426. )
  427. self.assertHTMLEqual(f['message'].as_text(), '<input type="text" name="message" required />')
  428. self.assertHTMLEqual(f['message'].as_hidden(), '<input type="hidden" name="message" />')
  429. # The 'widget' parameter to a Field can also be an instance:
  430. class ContactForm(Form):
  431. subject = CharField()
  432. message = CharField(widget=Textarea(attrs={'rows': 80, 'cols': 20}))
  433. f = ContactForm(auto_id=False)
  434. self.assertHTMLEqual(str(f['message']), '<textarea name="message" rows="80" cols="20" required></textarea>')
  435. # Instance-level attrs are *not* carried over to as_textarea(), as_text() and
  436. # as_hidden():
  437. self.assertHTMLEqual(f['message'].as_text(), '<input type="text" name="message" required />')
  438. f = ContactForm({'subject': 'Hello', 'message': 'I love you.'}, auto_id=False)
  439. self.assertHTMLEqual(
  440. f['subject'].as_textarea(),
  441. '<textarea rows="10" cols="40" name="subject" required>Hello</textarea>'
  442. )
  443. self.assertHTMLEqual(
  444. f['message'].as_text(),
  445. '<input type="text" name="message" value="I love you." required />',
  446. )
  447. self.assertHTMLEqual(f['message'].as_hidden(), '<input type="hidden" name="message" value="I love you." />')
  448. def test_forms_with_choices(self):
  449. # For a form with a <select>, use ChoiceField:
  450. class FrameworkForm(Form):
  451. name = CharField()
  452. language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')])
  453. f = FrameworkForm(auto_id=False)
  454. self.assertHTMLEqual(str(f['language']), """<select name="language" required>
  455. <option value="P">Python</option>
  456. <option value="J">Java</option>
  457. </select>""")
  458. f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
  459. self.assertHTMLEqual(str(f['language']), """<select name="language" required>
  460. <option value="P" selected="selected">Python</option>
  461. <option value="J">Java</option>
  462. </select>""")
  463. # A subtlety: If one of the choices' value is the empty string and the form is
  464. # unbound, then the <option> for the empty-string choice will get selected="selected".
  465. class FrameworkForm(Form):
  466. name = CharField()
  467. language = ChoiceField(choices=[('', '------'), ('P', 'Python'), ('J', 'Java')])
  468. f = FrameworkForm(auto_id=False)
  469. self.assertHTMLEqual(str(f['language']), """<select name="language" required>
  470. <option value="" selected="selected">------</option>
  471. <option value="P">Python</option>
  472. <option value="J">Java</option>
  473. </select>""")
  474. # You can specify widget attributes in the Widget constructor.
  475. class FrameworkForm(Form):
  476. name = CharField()
  477. language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=Select(attrs={'class': 'foo'}))
  478. f = FrameworkForm(auto_id=False)
  479. self.assertHTMLEqual(str(f['language']), """<select class="foo" name="language" required>
  480. <option value="P">Python</option>
  481. <option value="J">Java</option>
  482. </select>""")
  483. f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
  484. self.assertHTMLEqual(str(f['language']), """<select class="foo" name="language" required>
  485. <option value="P" selected="selected">Python</option>
  486. <option value="J">Java</option>
  487. </select>""")
  488. # When passing a custom widget instance to ChoiceField, note that setting
  489. # 'choices' on the widget is meaningless. The widget will use the choices
  490. # defined on the Field, not the ones defined on the Widget.
  491. class FrameworkForm(Form):
  492. name = CharField()
  493. language = ChoiceField(
  494. choices=[('P', 'Python'), ('J', 'Java')],
  495. widget=Select(choices=[('R', 'Ruby'), ('P', 'Perl')], attrs={'class': 'foo'}),
  496. )
  497. f = FrameworkForm(auto_id=False)
  498. self.assertHTMLEqual(str(f['language']), """<select class="foo" name="language" required>
  499. <option value="P">Python</option>
  500. <option value="J">Java</option>
  501. </select>""")
  502. f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
  503. self.assertHTMLEqual(str(f['language']), """<select class="foo" name="language" required>
  504. <option value="P" selected="selected">Python</option>
  505. <option value="J">Java</option>
  506. </select>""")
  507. # You can set a ChoiceField's choices after the fact.
  508. class FrameworkForm(Form):
  509. name = CharField()
  510. language = ChoiceField()
  511. f = FrameworkForm(auto_id=False)
  512. self.assertHTMLEqual(str(f['language']), """<select name="language" required>
  513. </select>""")
  514. f.fields['language'].choices = [('P', 'Python'), ('J', 'Java')]
  515. self.assertHTMLEqual(str(f['language']), """<select name="language" required>
  516. <option value="P">Python</option>
  517. <option value="J">Java</option>
  518. </select>""")
  519. def test_forms_with_radio(self):
  520. # Add widget=RadioSelect to use that widget with a ChoiceField.
  521. class FrameworkForm(Form):
  522. name = CharField()
  523. language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=RadioSelect)
  524. f = FrameworkForm(auto_id=False)
  525. self.assertHTMLEqual(str(f['language']), """<ul>
  526. <li><label><input type="radio" name="language" value="P" required /> Python</label></li>
  527. <li><label><input type="radio" name="language" value="J" required /> Java</label></li>
  528. </ul>""")
  529. self.assertHTMLEqual(f.as_table(), """<tr><th>Name:</th><td><input type="text" name="name" required /></td></tr>
  530. <tr><th>Language:</th><td><ul>
  531. <li><label><input type="radio" name="language" value="P" required /> Python</label></li>
  532. <li><label><input type="radio" name="language" value="J" required /> Java</label></li>
  533. </ul></td></tr>""")
  534. self.assertHTMLEqual(f.as_ul(), """<li>Name: <input type="text" name="name" required /></li>
  535. <li>Language: <ul>
  536. <li><label><input type="radio" name="language" value="P" required /> Python</label></li>
  537. <li><label><input type="radio" name="language" value="J" required /> Java</label></li>
  538. </ul></li>""")
  539. # Regarding auto_id and <label>, RadioSelect is a special case. Each radio button
  540. # gets a distinct ID, formed by appending an underscore plus the button's
  541. # zero-based index.
  542. f = FrameworkForm(auto_id='id_%s')
  543. self.assertHTMLEqual(
  544. str(f['language']),
  545. """<ul id="id_language">
  546. <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required />
  547. Python</label></li>
  548. <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required />
  549. Java</label></li>
  550. </ul>"""
  551. )
  552. # When RadioSelect is used with auto_id, and the whole form is printed using
  553. # either as_table() or as_ul(), the label for the RadioSelect will point to the
  554. # ID of the *first* radio button.
  555. self.assertHTMLEqual(
  556. f.as_table(),
  557. """<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name" required /></td></tr>
  558. <tr><th><label for="id_language_0">Language:</label></th><td><ul id="id_language">
  559. <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required />
  560. Python</label></li>
  561. <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required />
  562. Java</label></li>
  563. </ul></td></tr>"""
  564. )
  565. self.assertHTMLEqual(
  566. f.as_ul(),
  567. """<li><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" required /></li>
  568. <li><label for="id_language_0">Language:</label> <ul id="id_language">
  569. <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required />
  570. Python</label></li>
  571. <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required />
  572. Java</label></li>
  573. </ul></li>"""
  574. )
  575. self.assertHTMLEqual(
  576. f.as_p(),
  577. """<p><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" required /></p>
  578. <p><label for="id_language_0">Language:</label> <ul id="id_language">
  579. <li><label for="id_language_0"><input type="radio" id="id_language_0" value="P" name="language" required />
  580. Python</label></li>
  581. <li><label for="id_language_1"><input type="radio" id="id_language_1" value="J" name="language" required />
  582. Java</label></li>
  583. </ul></p>"""
  584. )
  585. # Test iterating on individual radios in a template
  586. t = Template('{% for radio in form.language %}<div class="myradio">{{ radio }}</div>{% endfor %}')
  587. self.assertHTMLEqual(
  588. t.render(Context({'form': f})),
  589. """<div class="myradio"><label for="id_language_0">
  590. <input id="id_language_0" name="language" type="radio" value="P" required /> Python</label></div>
  591. <div class="myradio"><label for="id_language_1">
  592. <input id="id_language_1" name="language" type="radio" value="J" required /> Java</label></div>"""
  593. )
  594. def test_form_with_iterable_boundfield(self):
  595. class BeatleForm(Form):
  596. name = ChoiceField(
  597. choices=[('john', 'John'), ('paul', 'Paul'), ('george', 'George'), ('ringo', 'Ringo')],
  598. widget=RadioSelect,
  599. )
  600. f = BeatleForm(auto_id=False)
  601. self.assertHTMLEqual(
  602. '\n'.join(str(bf) for bf in f['name']),
  603. """<label><input type="radio" name="name" value="john" required /> John</label>
  604. <label><input type="radio" name="name" value="paul" required /> Paul</label>
  605. <label><input type="radio" name="name" value="george" required /> George</label>
  606. <label><input type="radio" name="name" value="ringo" required /> Ringo</label>"""
  607. )
  608. self.assertHTMLEqual(
  609. '\n'.join('<div>%s</div>' % bf for bf in f['name']),
  610. """<div><label><input type="radio" name="name" value="john" required /> John</label></div>
  611. <div><label><input type="radio" name="name" value="paul" required /> Paul</label></div>
  612. <div><label><input type="radio" name="name" value="george" required /> George</label></div>
  613. <div><label><input type="radio" name="name" value="ringo" required /> Ringo</label></div>"""
  614. )
  615. def test_form_with_noniterable_boundfield(self):
  616. # You can iterate over any BoundField, not just those with widget=RadioSelect.
  617. class BeatleForm(Form):
  618. name = CharField()
  619. f = BeatleForm(auto_id=False)
  620. self.assertHTMLEqual('\n'.join(str(bf) for bf in f['name']), '<input type="text" name="name" required />')
  621. def test_boundfield_slice(self):
  622. class BeatleForm(Form):
  623. name = ChoiceField(
  624. choices=[('john', 'John'), ('paul', 'Paul'), ('george', 'George'), ('ringo', 'Ringo')],
  625. widget=RadioSelect,
  626. )
  627. f = BeatleForm()
  628. bf = f['name']
  629. self.assertEqual(
  630. [str(item) for item in bf[1:]],
  631. [str(bf[1]), str(bf[2]), str(bf[3])],
  632. )
  633. def test_forms_with_multiple_choice(self):
  634. # MultipleChoiceField is a special case, as its data is required to be a list:
  635. class SongForm(Form):
  636. name = CharField()
  637. composers = MultipleChoiceField()
  638. f = SongForm(auto_id=False)
  639. self.assertHTMLEqual(str(f['composers']), """<select multiple="multiple" name="composers" required>
  640. </select>""")
  641. class SongForm(Form):
  642. name = CharField()
  643. composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')])
  644. f = SongForm(auto_id=False)
  645. self.assertHTMLEqual(str(f['composers']), """<select multiple="multiple" name="composers" required>
  646. <option value="J">John Lennon</option>
  647. <option value="P">Paul McCartney</option>
  648. </select>""")
  649. f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False)
  650. self.assertHTMLEqual(str(f['name']), '<input type="text" name="name" value="Yesterday" required />')
  651. self.assertHTMLEqual(str(f['composers']), """<select multiple="multiple" name="composers" required>
  652. <option value="J">John Lennon</option>
  653. <option value="P" selected="selected">Paul McCartney</option>
  654. </select>""")
  655. def test_form_with_disabled_fields(self):
  656. class PersonForm(Form):
  657. name = CharField()
  658. birthday = DateField(disabled=True)
  659. class PersonFormFieldInitial(Form):
  660. name = CharField()
  661. birthday = DateField(disabled=True, initial=datetime.date(1974, 8, 16))
  662. # Disabled fields are generally not transmitted by user agents.
  663. # The value from the form's initial data is used.
  664. f1 = PersonForm({'name': 'John Doe'}, initial={'birthday': datetime.date(1974, 8, 16)})
  665. f2 = PersonFormFieldInitial({'name': 'John Doe'})
  666. for form in (f1, f2):
  667. self.assertTrue(form.is_valid())
  668. self.assertEqual(
  669. form.cleaned_data,
  670. {'birthday': datetime.date(1974, 8, 16), 'name': 'John Doe'}
  671. )
  672. # Values provided in the form's data are ignored.
  673. data = {'name': 'John Doe', 'birthday': '1984-11-10'}
  674. f1 = PersonForm(data, initial={'birthday': datetime.date(1974, 8, 16)})
  675. f2 = PersonFormFieldInitial(data)
  676. for form in (f1, f2):
  677. self.assertTrue(form.is_valid())
  678. self.assertEqual(
  679. form.cleaned_data,
  680. {'birthday': datetime.date(1974, 8, 16), 'name': 'John Doe'}
  681. )
  682. # Initial data remains present on invalid forms.
  683. data = {}
  684. f1 = PersonForm(data, initial={'birthday': datetime.date(1974, 8, 16)})
  685. f2 = PersonFormFieldInitial(data)
  686. for form in (f1, f2):
  687. self.assertFalse(form.is_valid())
  688. self.assertEqual(form['birthday'].value(), datetime.date(1974, 8, 16))
  689. def test_hidden_data(self):
  690. class SongForm(Form):
  691. name = CharField()
  692. composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')])
  693. # MultipleChoiceField rendered as_hidden() is a special case. Because it can
  694. # have multiple values, its as_hidden() renders multiple <input type="hidden">
  695. # tags.
  696. f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False)
  697. self.assertHTMLEqual(f['composers'].as_hidden(), '<input type="hidden" name="composers" value="P" />')
  698. f = SongForm({'name': 'From Me To You', 'composers': ['P', 'J']}, auto_id=False)
  699. self.assertHTMLEqual(f['composers'].as_hidden(), """<input type="hidden" name="composers" value="P" />
  700. <input type="hidden" name="composers" value="J" />""")
  701. # DateTimeField rendered as_hidden() is special too
  702. class MessageForm(Form):
  703. when = SplitDateTimeField()
  704. f = MessageForm({'when_0': '1992-01-01', 'when_1': '01:01'})
  705. self.assertTrue(f.is_valid())
  706. self.assertHTMLEqual(
  707. str(f['when']),
  708. '<input type="text" name="when_0" value="1992-01-01" id="id_when_0" required />'
  709. '<input type="text" name="when_1" value="01:01" id="id_when_1" required />'
  710. )
  711. self.assertHTMLEqual(
  712. f['when'].as_hidden(),
  713. '<input type="hidden" name="when_0" value="1992-01-01" id="id_when_0" />'
  714. '<input type="hidden" name="when_1" value="01:01" id="id_when_1" />'
  715. )
  716. def test_multiple_choice_checkbox(self):
  717. # MultipleChoiceField can also be used with the CheckboxSelectMultiple widget.
  718. class SongForm(Form):
  719. name = CharField()
  720. composers = MultipleChoiceField(
  721. choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')],
  722. widget=CheckboxSelectMultiple,
  723. )
  724. f = SongForm(auto_id=False)
  725. self.assertHTMLEqual(str(f['composers']), """<ul>
  726. <li><label><input type="checkbox" name="composers" value="J" /> John Lennon</label></li>
  727. <li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
  728. </ul>""")
  729. f = SongForm({'composers': ['J']}, auto_id=False)
  730. self.assertHTMLEqual(str(f['composers']), """<ul>
  731. <li><label><input checked type="checkbox" name="composers" value="J" /> John Lennon</label></li>
  732. <li><label><input type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
  733. </ul>""")
  734. f = SongForm({'composers': ['J', 'P']}, auto_id=False)
  735. self.assertHTMLEqual(str(f['composers']), """<ul>
  736. <li><label><input checked type="checkbox" name="composers" value="J" /> John Lennon</label></li>
  737. <li><label><input checked type="checkbox" name="composers" value="P" /> Paul McCartney</label></li>
  738. </ul>""")
  739. # Test iterating on individual checkboxes in a template
  740. t = Template('{% for checkbox in form.composers %}<div class="mycheckbox">{{ checkbox }}</div>{% endfor %}')
  741. self.assertHTMLEqual(t.render(Context({'form': f})), """<div class="mycheckbox"><label>
  742. <input checked name="composers" type="checkbox" value="J" /> John Lennon</label></div>
  743. <div class="mycheckbox"><label>
  744. <input checked name="composers" type="checkbox" value="P" /> Paul McCartney</label></div>""")
  745. def test_checkbox_auto_id(self):
  746. # Regarding auto_id, CheckboxSelectMultiple is a special case. Each checkbox
  747. # gets a distinct ID, formed by appending an underscore plus the checkbox's
  748. # zero-based index.
  749. class SongForm(Form):
  750. name = CharField()
  751. composers = MultipleChoiceField(
  752. choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')],
  753. widget=CheckboxSelectMultiple,
  754. )
  755. f = SongForm(auto_id='%s_id')
  756. self.assertHTMLEqual(
  757. str(f['composers']),
  758. """<ul id="composers_id">
  759. <li><label for="composers_id_0">
  760. <input type="checkbox" name="composers" value="J" id="composers_id_0" /> John Lennon</label></li>
  761. <li><label for="composers_id_1">
  762. <input type="checkbox" name="composers" value="P" id="composers_id_1" /> Paul McCartney</label></li>
  763. </ul>"""
  764. )
  765. def test_multiple_choice_list_data(self):
  766. # Data for a MultipleChoiceField should be a list. QueryDict and
  767. # MultiValueDict conveniently work with this.
  768. class SongForm(Form):
  769. name = CharField()
  770. composers = MultipleChoiceField(
  771. choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')],
  772. widget=CheckboxSelectMultiple,
  773. )
  774. data = {'name': 'Yesterday', 'composers': ['J', 'P']}
  775. f = SongForm(data)
  776. self.assertEqual(f.errors, {})
  777. data = QueryDict('name=Yesterday&composers=J&composers=P')
  778. f = SongForm(data)
  779. self.assertEqual(f.errors, {})
  780. data = MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P']))
  781. f = SongForm(data)
  782. self.assertEqual(f.errors, {})
  783. # SelectMultiple uses ducktyping so that MultiValueDictLike.getlist()
  784. # is called.
  785. f = SongForm(MultiValueDictLike({'name': 'Yesterday', 'composers': 'J'}))
  786. self.assertEqual(f.errors, {})
  787. self.assertEqual(f.cleaned_data['composers'], ['J'])
  788. def test_multiple_hidden(self):
  789. class SongForm(Form):
  790. name = CharField()
  791. composers = MultipleChoiceField(
  792. choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')],
  793. widget=CheckboxSelectMultiple,
  794. )
  795. # The MultipleHiddenInput widget renders multiple values as hidden fields.
  796. class SongFormHidden(Form):
  797. name = CharField()
  798. composers = MultipleChoiceField(
  799. choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')],
  800. widget=MultipleHiddenInput,
  801. )
  802. f = SongFormHidden(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])), auto_id=False)
  803. self.assertHTMLEqual(
  804. f.as_ul(),
  805. """<li>Name: <input type="text" name="name" value="Yesterday" required />
  806. <input type="hidden" name="composers" value="J" />
  807. <input type="hidden" name="composers" value="P" /></li>"""
  808. )
  809. # When using CheckboxSelectMultiple, the framework expects a list of input and
  810. # returns a list of input.
  811. f = SongForm({'name': 'Yesterday'}, auto_id=False)
  812. self.assertEqual(f.errors['composers'], ['This field is required.'])
  813. f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False)
  814. self.assertEqual(f.errors, {})
  815. self.assertEqual(f.cleaned_data['composers'], ['J'])
  816. self.assertEqual(f.cleaned_data['name'], 'Yesterday')
  817. f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False)
  818. self.assertEqual(f.errors, {})
  819. self.assertEqual(f.cleaned_data['composers'], ['J', 'P'])
  820. self.assertEqual(f.cleaned_data['name'], 'Yesterday')
  821. # MultipleHiddenInput uses ducktyping so that
  822. # MultiValueDictLike.getlist() is called.
  823. f = SongForm(MultiValueDictLike({'name': 'Yesterday', 'composers': 'J'}))
  824. self.assertEqual(f.errors, {})
  825. self.assertEqual(f.cleaned_data['composers'], ['J'])
  826. def test_escaping(self):
  827. # Validation errors are HTML-escaped when output as HTML.
  828. class EscapingForm(Form):
  829. special_name = CharField(label="<em>Special</em> Field")
  830. special_safe_name = CharField(label=mark_safe("<em>Special</em> Field"))
  831. def clean_special_name(self):
  832. raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name'])
  833. def clean_special_safe_name(self):
  834. raise ValidationError(
  835. mark_safe("'<b>%s</b>' is a safe string" % self.cleaned_data['special_safe_name'])
  836. )
  837. f = EscapingForm({
  838. 'special_name':
  839. "Nothing to escape",
  840. 'special_safe_name': "Nothing to escape",
  841. }, auto_id=False)
  842. self.assertHTMLEqual(
  843. f.as_table(),
  844. """<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td>
  845. <ul class="errorlist"><li>Something&#39;s wrong with &#39;Nothing to escape&#39;</li></ul>
  846. <input type="text" name="special_name" value="Nothing to escape" required /></td></tr>
  847. <tr><th><em>Special</em> Field:</th><td>
  848. <ul class="errorlist"><li>'<b>Nothing to escape</b>' is a safe string</li></ul>
  849. <input type="text" name="special_safe_name" value="Nothing to escape" required /></td></tr>"""
  850. )
  851. f = EscapingForm({
  852. 'special_name': "Should escape < & > and <script>alert('xss')</script>",
  853. 'special_safe_name': "<i>Do not escape</i>"
  854. }, auto_id=False)
  855. self.assertHTMLEqual(
  856. f.as_table(),
  857. """<tr><th>&lt;em&gt;Special&lt;/em&gt; Field:</th><td>
  858. <ul class="errorlist"><li>Something&#39;s wrong with &#39;Should escape &lt; &amp; &gt; and
  859. &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;&#39;</li></ul>
  860. <input type="text" name="special_name"
  861. value="Should escape &lt; &amp; &gt; and &lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;" required /></td></tr>
  862. <tr><th><em>Special</em> Field:</th><td>
  863. <ul class="errorlist"><li>'<b><i>Do not escape</i></b>' is a safe string</li></ul>
  864. <input type="text" name="special_safe_name" value="&lt;i&gt;Do not escape&lt;/i&gt;" required /></td></tr>"""
  865. )
  866. def test_validating_multiple_fields(self):
  867. # There are a couple of ways to do multiple-field validation. If you want the
  868. # validation message to be associated with a particular field, implement the
  869. # clean_XXX() method on the Form, where XXX is the field name. As in
  870. # Field.clean(), the clean_XXX() method should return the cleaned value. In the
  871. # clean_XXX() method, you have access to self.cleaned_data, which is a dictionary
  872. # of all the data that has been cleaned *so far*, in order by the fields,
  873. # including the current field (e.g., the field XXX if you're in clean_XXX()).
  874. class UserRegistration(Form):
  875. username = CharField(max_length=10)
  876. password1 = CharField(widget=PasswordInput)
  877. password2 = CharField(widget=PasswordInput)
  878. def clean_password2(self):
  879. if (self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and
  880. self.cleaned_data['password1'] != self.cleaned_data['password2']):
  881. raise ValidationError('Please make sure your passwords match.')
  882. return self.cleaned_data['password2']
  883. f = UserRegistration(auto_id=False)
  884. self.assertEqual(f.errors, {})
  885. f = UserRegistration({}, auto_id=False)
  886. self.assertEqual(f.errors['username'], ['This field is required.'])
  887. self.assertEqual(f.errors['password1'], ['This field is required.'])
  888. self.assertEqual(f.errors['password2'], ['This field is required.'])
  889. f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
  890. self.assertEqual(f.errors['password2'], ['Please make sure your passwords match.'])
  891. f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
  892. self.assertEqual(f.errors, {})
  893. self.assertEqual(f.cleaned_data['username'], 'adrian')
  894. self.assertEqual(f.cleaned_data['password1'], 'foo')
  895. self.assertEqual(f.cleaned_data['password2'], 'foo')
  896. # Another way of doing multiple-field validation is by implementing the
  897. # Form's clean() method. Usually ValidationError raised by that method
  898. # will not be associated with a particular field and will have a
  899. # special-case association with the field named '__all__'. It's
  900. # possible to associate the errors to particular field with the
  901. # Form.add_error() method or by passing a dictionary that maps each
  902. # field to one or more errors.
  903. #
  904. # Note that in Form.clean(), you have access to self.cleaned_data, a
  905. # dictionary of all the fields/values that have *not* raised a
  906. # ValidationError. Also note Form.clean() is required to return a
  907. # dictionary of all clean data.
  908. class UserRegistration(Form):
  909. username = CharField(max_length=10)
  910. password1 = CharField(widget=PasswordInput)
  911. password2 = CharField(widget=PasswordInput)
  912. def clean(self):
  913. # Test raising a ValidationError as NON_FIELD_ERRORS.
  914. if (self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and
  915. self.cleaned_data['password1'] != self.cleaned_data['password2']):
  916. raise ValidationError('Please make sure your passwords match.')
  917. # Test raising ValidationError that targets multiple fields.
  918. errors = {}
  919. if self.cleaned_data.get('password1') == 'FORBIDDEN_VALUE':
  920. errors['password1'] = 'Forbidden value.'
  921. if self.cleaned_data.get('password2') == 'FORBIDDEN_VALUE':
  922. errors['password2'] = ['Forbidden value.']
  923. if errors:
  924. raise ValidationError(errors)
  925. # Test Form.add_error()
  926. if self.cleaned_data.get('password1') == 'FORBIDDEN_VALUE2':
  927. self.add_error(None, 'Non-field error 1.')
  928. self.add_error('password1', 'Forbidden value 2.')
  929. if self.cleaned_data.get('password2') == 'FORBIDDEN_VALUE2':
  930. self.add_error('password2', 'Forbidden value