diff --git a/django/forms/fields.py b/django/forms/fields.py
index 4438812..940374b 100644
|
a
|
b
|
from io import BytesIO
|
| 18 | 18 | from django.core import validators |
| 19 | 19 | from django.core.exceptions import ValidationError |
| 20 | 20 | from django.forms.util import ErrorList, from_current_timezone, to_current_timezone |
| 21 | | from django.forms.widgets import (TextInput, PasswordInput, HiddenInput, |
| | 21 | from django.forms.widgets import ( |
| | 22 | TextInput, NumberInput, PasswordInput, EmailInput, URLInput, HiddenInput, |
| 22 | 23 | MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, |
| 23 | 24 | NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, |
| 24 | | SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION) |
| | 25 | SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION |
| | 26 | ) |
| 25 | 27 | from django.utils import formats |
| 26 | 28 | from django.utils.encoding import smart_text, force_text |
| 27 | 29 | from django.utils.ipv6 import clean_ipv6_address |
| … |
… |
class CharField(Field):
|
| 205 | 207 | return attrs |
| 206 | 208 | |
| 207 | 209 | class IntegerField(Field): |
| | 210 | widget = NumberInput |
| 208 | 211 | default_error_messages = { |
| 209 | 212 | 'invalid': _('Enter a whole number.'), |
| 210 | 213 | 'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'), |
| … |
… |
class IntegerField(Field):
|
| 236 | 239 | raise ValidationError(self.error_messages['invalid']) |
| 237 | 240 | return value |
| 238 | 241 | |
| | 242 | def widget_attrs(self, widget): |
| | 243 | attrs = super(IntegerField, self).widget_attrs(widget) |
| | 244 | if self.min_value: |
| | 245 | attrs['min'] = self.min_value |
| | 246 | if self.max_value: |
| | 247 | attrs['max'] = self.max_value |
| | 248 | return attrs |
| | 249 | |
| | 250 | |
| 239 | 251 | class FloatField(IntegerField): |
| 240 | 252 | default_error_messages = { |
| 241 | 253 | 'invalid': _('Enter a number.'), |
| … |
… |
class FloatField(IntegerField):
|
| 257 | 269 | raise ValidationError(self.error_messages['invalid']) |
| 258 | 270 | return value |
| 259 | 271 | |
| 260 | | class DecimalField(Field): |
| | 272 | def widget_attrs(self, widget): |
| | 273 | attrs = super(FloatField, self).widget_attrs(widget) |
| | 274 | attrs.setdefault('step', 'any') |
| | 275 | return attrs |
| | 276 | |
| | 277 | |
| | 278 | class DecimalField(IntegerField): |
| 261 | 279 | default_error_messages = { |
| 262 | 280 | 'invalid': _('Enter a number.'), |
| 263 | | 'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'), |
| 264 | | 'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'), |
| 265 | 281 | 'max_digits': _('Ensure that there are no more than %s digits in total.'), |
| 266 | 282 | 'max_decimal_places': _('Ensure that there are no more than %s decimal places.'), |
| 267 | 283 | 'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.') |
| 268 | 284 | } |
| 269 | 285 | |
| 270 | 286 | def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs): |
| 271 | | self.max_value, self.min_value = max_value, min_value |
| 272 | 287 | self.max_digits, self.decimal_places = max_digits, decimal_places |
| 273 | | Field.__init__(self, *args, **kwargs) |
| 274 | | |
| 275 | | if max_value is not None: |
| 276 | | self.validators.append(validators.MaxValueValidator(max_value)) |
| 277 | | if min_value is not None: |
| 278 | | self.validators.append(validators.MinValueValidator(min_value)) |
| | 288 | super(DecimalField, self).__init__(max_value, min_value, *args, **kwargs) |
| 279 | 289 | |
| 280 | 290 | def to_python(self, value): |
| 281 | 291 | """ |
| … |
… |
class DecimalField(Field):
|
| 324 | 334 | raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) |
| 325 | 335 | return value |
| 326 | 336 | |
| | 337 | def widget_attrs(self, widget): |
| | 338 | attrs = super(DecimalField, self).widget_attrs(widget) |
| | 339 | if self.max_digits: |
| | 340 | attrs['maxlength'] = self.max_digits + 1 # for the dot |
| | 341 | if self.decimal_places: |
| | 342 | attrs['step'] = '0.%s1' % ('0' * (self.decimal_places-1)) |
| | 343 | return attrs |
| | 344 | |
| | 345 | |
| 327 | 346 | class BaseTemporalField(Field): |
| 328 | 347 | |
| 329 | 348 | def __init__(self, input_formats=None, *args, **kwargs): |
| … |
… |
class RegexField(CharField):
|
| 460 | 479 | regex = property(_get_regex, _set_regex) |
| 461 | 480 | |
| 462 | 481 | class EmailField(CharField): |
| | 482 | widget = EmailInput |
| 463 | 483 | default_error_messages = { |
| 464 | 484 | 'invalid': _('Enter a valid email address.'), |
| 465 | 485 | } |
| … |
… |
class ImageField(FileField):
|
| 576 | 596 | return f |
| 577 | 597 | |
| 578 | 598 | class URLField(CharField): |
| | 599 | widget = URLInput |
| 579 | 600 | default_error_messages = { |
| 580 | 601 | 'invalid': _('Enter a valid URL.'), |
| 581 | 602 | } |
diff --git a/django/forms/widgets.py b/django/forms/widgets.py
index 763da0c..c6203f0 100644
|
a
|
b
|
from django.utils.safestring import mark_safe
|
| 22 | 22 | from django.utils import datetime_safe, formats, six |
| 23 | 23 | |
| 24 | 24 | __all__ = ( |
| 25 | | 'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'PasswordInput', |
| | 25 | 'Media', 'MediaDefiningClass', 'Widget', 'TextInput', |
| | 26 | 'EmailInput', 'URLInput', 'NumberInput', 'PasswordInput', |
| 26 | 27 | 'HiddenInput', 'MultipleHiddenInput', 'ClearableFileInput', |
| 27 | 28 | 'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput', |
| 28 | 29 | 'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', |
| … |
… |
class TextInput(Input):
|
| 270 | 271 | super(TextInput, self).__init__(attrs) |
| 271 | 272 | |
| 272 | 273 | |
| | 274 | class NumberInput(TextInput): |
| | 275 | input_type = 'number' |
| | 276 | |
| | 277 | |
| | 278 | class EmailInput(TextInput): |
| | 279 | input_type = 'email' |
| | 280 | |
| | 281 | |
| | 282 | class URLInput(TextInput): |
| | 283 | input_type = 'url' |
| | 284 | |
| | 285 | |
| 273 | 286 | class PasswordInput(TextInput): |
| 274 | 287 | input_type = 'password' |
| 275 | 288 | |
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
index 82a3ea9..9e96ab3 100644
|
a
|
b
|
We've specified ``auto_id=False`` to simplify the output::
|
| 112 | 112 | >>> f = CommentForm(auto_id=False) |
| 113 | 113 | >>> print(f) |
| 114 | 114 | <tr><th>Your name:</th><td><input type="text" name="name" /></td></tr> |
| 115 | | <tr><th>Your Web site:</th><td><input type="text" name="url" /></td></tr> |
| | 115 | <tr><th>Your Web site:</th><td><input type="url" name="url" /></td></tr> |
| 116 | 116 | <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> |
| 117 | 117 | |
| 118 | 118 | ``initial`` |
| … |
… |
field is initialized to a particular value. For example::
|
| 135 | 135 | >>> f = CommentForm(auto_id=False) |
| 136 | 136 | >>> print(f) |
| 137 | 137 | <tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr> |
| 138 | | <tr><th>Url:</th><td><input type="text" name="url" value="http://" /></td></tr> |
| | 138 | <tr><th>Url:</th><td><input type="url" name="url" value="http://" /></td></tr> |
| 139 | 139 | <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> |
| 140 | 140 | |
| 141 | 141 | You may be thinking, why not just pass a dictionary of the initial values as |
| … |
… |
and the HTML output will include any validation errors::
|
| 150 | 150 | >>> f = CommentForm(default_data, auto_id=False) |
| 151 | 151 | >>> print(f) |
| 152 | 152 | <tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr> |
| 153 | | <tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="text" name="url" value="http://" /></td></tr> |
| | 153 | <tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="url" name="url" value="http://" /></td></tr> |
| 154 | 154 | <tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" /></td></tr> |
| 155 | 155 | |
| 156 | 156 | This is why ``initial`` values are only displayed for unbound forms. For bound |
| … |
… |
fields. We've specified ``auto_id=False`` to simplify the output::
|
| 217 | 217 | >>> print(f.as_ul())) |
| 218 | 218 | <li>Subject: <input type="text" name="subject" maxlength="100" /> <span class="helptext">100 characters max.</span></li> |
| 219 | 219 | <li>Message: <input type="text" name="message" /></li> |
| 220 | | <li>Sender: <input type="text" name="sender" /> A valid email address, please.</li> |
| | 220 | <li>Sender: <input type="email" name="sender" /> A valid email address, please.</li> |
| 221 | 221 | <li>Cc myself: <input type="checkbox" name="cc_myself" /></li> |
| 222 | 222 | >>> print(f.as_p()) |
| 223 | 223 | <p>Subject: <input type="text" name="subject" maxlength="100" /> <span class="helptext">100 characters max.</span></p> |
| 224 | 224 | <p>Message: <input type="text" name="message" /></p> |
| 225 | | <p>Sender: <input type="text" name="sender" /> A valid email address, please.</p> |
| | 225 | <p>Sender: <input type="email" name="sender" /> A valid email address, please.</p> |
| 226 | 226 | <p>Cc myself: <input type="checkbox" name="cc_myself" /></p> |
| 227 | 227 | |
| 228 | 228 | ``error_messages`` |
| … |
… |
For each field, we describe the default widget used if you don't specify
|
| 450 | 450 | |
| 451 | 451 | .. class:: DecimalField(**kwargs) |
| 452 | 452 | |
| 453 | | * Default widget: ``TextInput`` |
| | 453 | * Default widget: ``NumberInput`` |
| 454 | 454 | * Empty value: ``None`` |
| 455 | 455 | * Normalizes to: A Python ``decimal``. |
| 456 | 456 | * Validates that the given value is a decimal. Leading and trailing |
| … |
… |
For each field, we describe the default widget used if you don't specify
|
| 485 | 485 | |
| 486 | 486 | .. class:: EmailField(**kwargs) |
| 487 | 487 | |
| 488 | | * Default widget: ``TextInput`` |
| | 488 | * Default widget: ``EmailInput`` |
| 489 | 489 | * Empty value: ``''`` (an empty string) |
| 490 | 490 | * Normalizes to: A Unicode object. |
| 491 | 491 | * Validates that the given value is a valid email address, using a |
| … |
… |
For each field, we describe the default widget used if you don't specify
|
| 576 | 576 | |
| 577 | 577 | .. class:: FloatField(**kwargs) |
| 578 | 578 | |
| 579 | | * Default widget: ``TextInput`` |
| | 579 | * Default widget: ``NumberInput`` |
| 580 | 580 | * Empty value: ``None`` |
| 581 | 581 | * Normalizes to: A Python float. |
| 582 | 582 | * Validates that the given value is an float. Leading and trailing |
| … |
… |
For each field, we describe the default widget used if you don't specify
|
| 617 | 617 | |
| 618 | 618 | .. class:: IntegerField(**kwargs) |
| 619 | 619 | |
| 620 | | * Default widget: ``TextInput`` |
| | 620 | * Default widget: ``NumberInput`` |
| 621 | 621 | * Empty value: ``None`` |
| 622 | 622 | * Normalizes to: A Python integer or long integer. |
| 623 | 623 | * Validates that the given value is an integer. Leading and trailing |
| … |
… |
For each field, we describe the default widget used if you don't specify
|
| 803 | 803 | |
| 804 | 804 | .. class:: URLField(**kwargs) |
| 805 | 805 | |
| 806 | | * Default widget: ``TextInput`` |
| | 806 | * Default widget: ``URLInput`` |
| 807 | 807 | * Empty value: ``''`` (an empty string) |
| 808 | 808 | * Normalizes to: A Unicode object. |
| 809 | 809 | * Validates that the given value is a valid URL. |
diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt
index 3c45893..33c3bf0 100644
|
a
|
b
|
provided for each widget will be rendered exactly the same::
|
| 139 | 139 | >>> f = CommentForm(auto_id=False) |
| 140 | 140 | >>> f.as_table() |
| 141 | 141 | <tr><th>Name:</th><td><input type="text" name="name" /></td></tr> |
| 142 | | <tr><th>Url:</th><td><input type="text" name="url"/></td></tr> |
| | 142 | <tr><th>Url:</th><td><input type="url" name="url"/></td></tr> |
| 143 | 143 | <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr> |
| 144 | 144 | |
| 145 | 145 | On a real Web page, you probably don't want every widget to look the same. You |
| … |
… |
Django will then include the extra attributes in the rendered output:
|
| 160 | 160 | >>> f = CommentForm(auto_id=False) |
| 161 | 161 | >>> f.as_table() |
| 162 | 162 | <tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr> |
| 163 | | <tr><th>Url:</th><td><input type="text" name="url"/></td></tr> |
| | 163 | <tr><th>Url:</th><td><input type="url" name="url"/></td></tr> |
| 164 | 164 | <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr> |
| 165 | 165 | |
| 166 | 166 | .. _styling-widget-classes: |
| … |
… |
These widgets make use of the HTML elements ``input`` and ``textarea``.
|
| 280 | 280 | |
| 281 | 281 | Text input: ``<input type='text' ...>`` |
| 282 | 282 | |
| | 283 | ``NumberInput`` |
| | 284 | ~~~~~~~~~~~~~~~ |
| | 285 | |
| | 286 | .. class:: NumberInput |
| | 287 | |
| | 288 | .. versionadded:: 1.5 |
| | 289 | |
| | 290 | Text input: ``<input type='number' ...>`` |
| | 291 | |
| | 292 | ``EmailInput`` |
| | 293 | ~~~~~~~~~~~~~~ |
| | 294 | |
| | 295 | .. class:: EmailInput |
| | 296 | |
| | 297 | .. versionadded:: 1.5 |
| | 298 | |
| | 299 | Text input: ``<input type='email' ...>`` |
| | 300 | |
| | 301 | ``URLInput`` |
| | 302 | ~~~~~~~~~~~~ |
| | 303 | |
| | 304 | .. class:: URLInput |
| | 305 | |
| | 306 | .. versionadded:: 1.5 |
| | 307 | |
| | 308 | Text input: ``<input type='url' ...>`` |
| | 309 | |
| 283 | 310 | ``PasswordInput`` |
| 284 | 311 | ~~~~~~~~~~~~~~~~~ |
| 285 | 312 | |
diff --git a/docs/releases/1.5.txt b/docs/releases/1.5.txt
index c395921..cc14683 100644
|
a
|
b
|
Django 1.5 also includes several smaller improvements worth noting:
|
| 184 | 184 | look up permissions by using ``{% if 'someapp.someperm' in perms %}`` |
| 185 | 185 | in templates. |
| 186 | 186 | |
| | 187 | * The default widgets for :class:`~django.forms.EmailField`, |
| | 188 | :class:`~django.forms.URLField`, :class:`~django.forms.IntegerField`, |
| | 189 | :class:`~django.forms.FloatField and :class:`~django.forms.DecimalField use |
| | 190 | the new type attributes available in HTML5 (type='email', type='url', |
| | 191 | type='number'). |
| | 192 | |
| 187 | 193 | Backwards incompatible changes in 1.5 |
| 188 | 194 | ===================================== |
| 189 | 195 | |
diff --git a/tests/modeltests/model_forms/tests.py b/tests/modeltests/model_forms/tests.py
index 038ce32..9898082 100644
|
a
|
b
|
class OldFormForXTests(TestCase):
|
| 1088 | 1088 | <option value="%s">Joe Better</option> |
| 1089 | 1089 | <option value="%s">Mike Royko</option> |
| 1090 | 1090 | </select></p> |
| 1091 | | <p><label for="id_age">Age:</label> <input type="text" name="age" id="id_age" /></p>''' % (w_woodward.pk, w_bernstein.pk, bw.pk, w_royko.pk)) |
| | 1091 | <p><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" /></p>''' % (w_woodward.pk, w_bernstein.pk, bw.pk, w_royko.pk)) |
| 1092 | 1092 | |
| 1093 | 1093 | data = { |
| 1094 | 1094 | 'writer': six.text_type(w_woodward.pk), |
| … |
… |
class OldFormForXTests(TestCase):
|
| 1106 | 1106 | <option value="%s">Joe Better</option> |
| 1107 | 1107 | <option value="%s">Mike Royko</option> |
| 1108 | 1108 | </select></p> |
| 1109 | | <p><label for="id_age">Age:</label> <input type="text" name="age" value="65" id="id_age" /></p>''' % (w_woodward.pk, w_bernstein.pk, bw.pk, w_royko.pk)) |
| | 1109 | <p><label for="id_age">Age:</label> <input type="number" name="age" value="65" id="id_age" /></p>''' % (w_woodward.pk, w_bernstein.pk, bw.pk, w_royko.pk)) |
| 1110 | 1110 | |
| 1111 | 1111 | def test_phone_number_field(self): |
| 1112 | 1112 | f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'}) |
diff --git a/tests/modeltests/model_formsets/tests.py b/tests/modeltests/model_formsets/tests.py
index e28560b..c4c60c0 100644
|
a
|
b
|
class ModelFormsetTest(TestCase):
|
| 384 | 384 | self.assertEqual(len(formset.forms), 1) |
| 385 | 385 | self.assertHTMLEqual(formset.forms[0].as_p(), |
| 386 | 386 | '<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></p>\n' |
| 387 | | '<p><label for="id_form-0-write_speed">Write speed:</label> <input type="text" name="form-0-write_speed" id="id_form-0-write_speed" /><input type="hidden" name="form-0-author_ptr" id="id_form-0-author_ptr" /></p>') |
| | 387 | '<p><label for="id_form-0-write_speed">Write speed:</label> <input type="number" name="form-0-write_speed" id="id_form-0-write_speed" /><input type="hidden" name="form-0-author_ptr" id="id_form-0-author_ptr" /></p>') |
| 388 | 388 | |
| 389 | 389 | data = { |
| 390 | 390 | 'form-TOTAL_FORMS': '1', # the number of forms rendered |
| … |
… |
class ModelFormsetTest(TestCase):
|
| 407 | 407 | self.assertEqual(len(formset.forms), 2) |
| 408 | 408 | self.assertHTMLEqual(formset.forms[0].as_p(), |
| 409 | 409 | '<p><label for="id_form-0-name">Name:</label> <input id="id_form-0-name" type="text" name="form-0-name" value="Ernest Hemingway" maxlength="100" /></p>\n' |
| 410 | | '<p><label for="id_form-0-write_speed">Write speed:</label> <input type="text" name="form-0-write_speed" value="10" id="id_form-0-write_speed" /><input type="hidden" name="form-0-author_ptr" value="%d" id="id_form-0-author_ptr" /></p>' % hemingway_id) |
| | 410 | '<p><label for="id_form-0-write_speed">Write speed:</label> <input type="number" name="form-0-write_speed" value="10" id="id_form-0-write_speed" /><input type="hidden" name="form-0-author_ptr" value="%d" id="id_form-0-author_ptr" /></p>' % hemingway_id) |
| 411 | 411 | self.assertHTMLEqual(formset.forms[1].as_p(), |
| 412 | 412 | '<p><label for="id_form-1-name">Name:</label> <input id="id_form-1-name" type="text" name="form-1-name" maxlength="100" /></p>\n' |
| 413 | | '<p><label for="id_form-1-write_speed">Write speed:</label> <input type="text" name="form-1-write_speed" id="id_form-1-write_speed" /><input type="hidden" name="form-1-author_ptr" id="id_form-1-author_ptr" /></p>') |
| | 413 | '<p><label for="id_form-1-write_speed">Write speed:</label> <input type="number" name="form-1-write_speed" id="id_form-1-write_speed" /><input type="hidden" name="form-1-author_ptr" id="id_form-1-author_ptr" /></p>') |
| 414 | 414 | |
| 415 | 415 | data = { |
| 416 | 416 | 'form-TOTAL_FORMS': '2', # the number of forms rendered |
| … |
… |
class ModelFormsetTest(TestCase):
|
| 550 | 550 | formset = AuthorBooksFormSet2(instance=author) |
| 551 | 551 | self.assertEqual(len(formset.forms), 1) |
| 552 | 552 | self.assertHTMLEqual(formset.forms[0].as_p(), |
| 553 | | '<p><label for="id_bookwithcustompk_set-0-my_pk">My pk:</label> <input type="text" name="bookwithcustompk_set-0-my_pk" id="id_bookwithcustompk_set-0-my_pk" /></p>\n' |
| | 553 | '<p><label for="id_bookwithcustompk_set-0-my_pk">My pk:</label> <input id="id_bookwithcustompk_set-0-my_pk" type="number" name="bookwithcustompk_set-0-my_pk" maxlength="6" /></p>\n' |
| 554 | 554 | '<p><label for="id_bookwithcustompk_set-0-title">Title:</label> <input id="id_bookwithcustompk_set-0-title" type="text" name="bookwithcustompk_set-0-title" maxlength="100" /><input type="hidden" name="bookwithcustompk_set-0-author" value="1" id="id_bookwithcustompk_set-0-author" /></p>') |
| 555 | 555 | |
| 556 | 556 | data = { |
| … |
… |
class ModelFormsetTest(TestCase):
|
| 798 | 798 | '<option value="%d">Joe Perry at Giordanos</option>\n' |
| 799 | 799 | '<option value="%d">Jack Berry at Giordanos</option>\n' |
| 800 | 800 | '</select></p>\n' |
| 801 | | '<p><label for="id_form-0-age">Age:</label> <input type="text" name="form-0-age" id="id_form-0-age" /></p>' |
| | 801 | '<p><label for="id_form-0-age">Age:</label> <input type="number" name="form-0-age" id="id_form-0-age" /></p>' |
| 802 | 802 | % (owner1.auto_id, owner2.auto_id)) |
| 803 | 803 | |
| 804 | 804 | owner1 = Owner.objects.get(name='Joe Perry') |
| … |
… |
class ModelFormsetTest(TestCase):
|
| 808 | 808 | formset = FormSet(instance=owner1) |
| 809 | 809 | self.assertEqual(len(formset.forms), 1) |
| 810 | 810 | self.assertHTMLEqual(formset.forms[0].as_p(), |
| 811 | | '<p><label for="id_ownerprofile-0-age">Age:</label> <input type="text" name="ownerprofile-0-age" id="id_ownerprofile-0-age" /><input type="hidden" name="ownerprofile-0-owner" value="%d" id="id_ownerprofile-0-owner" /></p>' |
| | 811 | '<p><label for="id_ownerprofile-0-age">Age:</label> <input type="number" name="ownerprofile-0-age" id="id_ownerprofile-0-age" /><input type="hidden" name="ownerprofile-0-owner" value="%d" id="id_ownerprofile-0-owner" /></p>' |
| 812 | 812 | % owner1.auto_id) |
| 813 | 813 | |
| 814 | 814 | data = { |
| … |
… |
class ModelFormsetTest(TestCase):
|
| 829 | 829 | formset = FormSet(instance=owner1) |
| 830 | 830 | self.assertEqual(len(formset.forms), 1) |
| 831 | 831 | self.assertHTMLEqual(formset.forms[0].as_p(), |
| 832 | | '<p><label for="id_ownerprofile-0-age">Age:</label> <input type="text" name="ownerprofile-0-age" value="54" id="id_ownerprofile-0-age" /><input type="hidden" name="ownerprofile-0-owner" value="%d" id="id_ownerprofile-0-owner" /></p>' |
| | 832 | '<p><label for="id_ownerprofile-0-age">Age:</label> <input type="number" name="ownerprofile-0-age" value="54" id="id_ownerprofile-0-age" /><input type="hidden" name="ownerprofile-0-owner" value="%d" id="id_ownerprofile-0-owner" /></p>' |
| 833 | 833 | % owner1.auto_id) |
| 834 | 834 | |
| 835 | 835 | data = { |
| … |
… |
class ModelFormsetTest(TestCase):
|
| 985 | 985 | result = re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)?', '__DATETIME__', result) |
| 986 | 986 | self.assertHTMLEqual(result, |
| 987 | 987 | '<p><label for="id_membership_set-0-date_joined">Date joined:</label> <input type="text" name="membership_set-0-date_joined" value="__DATETIME__" id="id_membership_set-0-date_joined" /><input type="hidden" name="initial-membership_set-0-date_joined" value="__DATETIME__" id="initial-membership_set-0-id_membership_set-0-date_joined" /></p>\n' |
| 988 | | '<p><label for="id_membership_set-0-karma">Karma:</label> <input type="text" name="membership_set-0-karma" id="id_membership_set-0-karma" /><input type="hidden" name="membership_set-0-person" value="%d" id="id_membership_set-0-person" /><input type="hidden" name="membership_set-0-id" id="id_membership_set-0-id" /></p>' |
| | 988 | '<p><label for="id_membership_set-0-karma">Karma:</label> <input type="number" name="membership_set-0-karma" id="id_membership_set-0-karma" /><input type="hidden" name="membership_set-0-person" value="%d" id="id_membership_set-0-person" /><input type="hidden" name="membership_set-0-id" id="id_membership_set-0-id" /></p>' |
| 989 | 989 | % person.id) |
| 990 | 990 | |
| 991 | 991 | # test for validation with callable defaults. Validations rely on hidden fields |
diff --git a/tests/regressiontests/forms/tests/extra.py b/tests/regressiontests/forms/tests/extra.py
index 44d6778..255f8b2 100644
|
a
|
b
|
class FormsExtraTestCase(TestCase, AssertFormErrorsMixin):
|
| 614 | 614 | f = CommentForm(data, auto_id=False, error_class=DivErrorList) |
| 615 | 615 | self.assertHTMLEqual(f.as_p(), """<p>Name: <input type="text" name="name" maxlength="50" /></p> |
| 616 | 616 | <div class="errorlist"><div class="error">Enter a valid email address.</div></div> |
| 617 | | <p>Email: <input type="text" name="email" value="invalid" /></p> |
| | 617 | <p>Email: <input type="email" name="email" value="invalid" /></p> |
| 618 | 618 | <div class="errorlist"><div class="error">This field is required.</div></div> |
| 619 | 619 | <p>Comment: <input type="text" name="comment" /></p>""") |
| 620 | 620 | |
diff --git a/tests/regressiontests/forms/tests/fields.py b/tests/regressiontests/forms/tests/fields.py
index 8695256..2890422 100644
|
a
|
b
|
def fix_os_paths(x):
|
| 51 | 51 | |
| 52 | 52 | class FieldsTests(SimpleTestCase): |
| 53 | 53 | |
| | 54 | def assertWidgetRendersTo(self, field, to): |
| | 55 | class _Form(Form): |
| | 56 | f = field |
| | 57 | self.assertEqual(str(_Form()['f']), to) |
| | 58 | |
| 54 | 59 | def test_field_sets_widget_is_required(self): |
| 55 | 60 | self.assertTrue(Field(required=True).widget.is_required) |
| 56 | 61 | self.assertFalse(Field(required=False).widget.is_required) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 124 | 129 | |
| 125 | 130 | def test_integerfield_1(self): |
| 126 | 131 | f = IntegerField() |
| | 132 | self.assertWidgetRendersTo(f, '<input type="number" name="f" id="id_f" />') |
| 127 | 133 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') |
| 128 | 134 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) |
| 129 | 135 | self.assertEqual(1, f.clean('1')) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 158 | 164 | |
| 159 | 165 | def test_integerfield_3(self): |
| 160 | 166 | f = IntegerField(max_value=10) |
| | 167 | self.assertWidgetRendersTo(f, '<input max="10" type="number" name="f" id="id_f" />') |
| 161 | 168 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) |
| 162 | 169 | self.assertEqual(1, f.clean(1)) |
| 163 | 170 | self.assertEqual(10, f.clean(10)) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 169 | 176 | |
| 170 | 177 | def test_integerfield_4(self): |
| 171 | 178 | f = IntegerField(min_value=10) |
| | 179 | self.assertWidgetRendersTo(f, '<input id="id_f" type="number" name="f" min="10" />') |
| 172 | 180 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) |
| 173 | 181 | self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 10.'", f.clean, 1) |
| 174 | 182 | self.assertEqual(10, f.clean(10)) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 180 | 188 | |
| 181 | 189 | def test_integerfield_5(self): |
| 182 | 190 | f = IntegerField(min_value=10, max_value=20) |
| | 191 | self.assertWidgetRendersTo(f, '<input id="id_f" max="20" type="number" name="f" min="10" />') |
| 183 | 192 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) |
| 184 | 193 | self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 10.'", f.clean, 1) |
| 185 | 194 | self.assertEqual(10, f.clean(10)) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 195 | 204 | |
| 196 | 205 | def test_floatfield_1(self): |
| 197 | 206 | f = FloatField() |
| | 207 | self.assertWidgetRendersTo(f, '<input step="any" type="number" name="f" id="id_f" />') |
| 198 | 208 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') |
| 199 | 209 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) |
| 200 | 210 | self.assertEqual(1.0, f.clean('1')) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 221 | 231 | |
| 222 | 232 | def test_floatfield_3(self): |
| 223 | 233 | f = FloatField(max_value=1.5, min_value=0.5) |
| | 234 | self.assertWidgetRendersTo(f, '<input step="any" name="f" min="0.5" max="1.5" type="number" id="id_f" />') |
| 224 | 235 | self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'", f.clean, '1.6') |
| 225 | 236 | self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'", f.clean, '0.4') |
| 226 | 237 | self.assertEqual(1.5, f.clean('1.5')) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 232 | 243 | |
| 233 | 244 | def test_decimalfield_1(self): |
| 234 | 245 | f = DecimalField(max_digits=4, decimal_places=2) |
| | 246 | self.assertWidgetRendersTo(f, '<input id="id_f" step="0.01" type="number" name="f" maxlength="5" />') |
| 235 | 247 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') |
| 236 | 248 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) |
| 237 | 249 | self.assertEqual(f.clean('1'), Decimal("1")) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 277 | 289 | |
| 278 | 290 | def test_decimalfield_3(self): |
| 279 | 291 | f = DecimalField(max_digits=4, decimal_places=2, max_value=Decimal('1.5'), min_value=Decimal('0.5')) |
| | 292 | self.assertWidgetRendersTo(f, '<input step="0.01" name="f" min="0.5" max="1.5" maxlength="5" type="number" id="id_f" />') |
| 280 | 293 | self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'", f.clean, '1.6') |
| 281 | 294 | self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'", f.clean, '0.4') |
| 282 | 295 | self.assertEqual(f.clean('1.5'), Decimal("1.5")) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 504 | 517 | |
| 505 | 518 | def test_emailfield_1(self): |
| 506 | 519 | f = EmailField() |
| | 520 | self.assertWidgetRendersTo(f, '<input type="email" name="f" id="id_f" />') |
| 507 | 521 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') |
| 508 | 522 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) |
| 509 | 523 | self.assertEqual('person@example.com', f.clean('person@example.com')) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 542 | 556 | |
| 543 | 557 | def test_emailfield_3(self): |
| 544 | 558 | f = EmailField(min_length=10, max_length=15) |
| | 559 | self.assertWidgetRendersTo(f, '<input id="id_f" type="email" name="f" maxlength="15" />') |
| 545 | 560 | self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 10 characters (it has 9).'", f.clean, 'a@foo.com') |
| 546 | 561 | self.assertEqual('alf@foo.com', f.clean('alf@foo.com')) |
| 547 | 562 | self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 15 characters (it has 20).'", f.clean, 'alf123456788@foo.com') |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 582 | 597 | |
| 583 | 598 | def test_urlfield_1(self): |
| 584 | 599 | f = URLField() |
| | 600 | self.assertWidgetRendersTo(f, '<input type="url" name="f" id="id_f" />') |
| 585 | 601 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '') |
| 586 | 602 | self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None) |
| 587 | 603 | self.assertEqual('http://localhost/', f.clean('http://localhost')) |
| … |
… |
class FieldsTests(SimpleTestCase):
|
| 633 | 649 | |
| 634 | 650 | def test_urlfield_5(self): |
| 635 | 651 | f = URLField(min_length=15, max_length=20) |
| | 652 | self.assertWidgetRendersTo(f, '<input id="id_f" type="url" name="f" maxlength="20" />') |
| 636 | 653 | self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 15 characters (it has 13).'", f.clean, 'http://f.com') |
| 637 | 654 | self.assertEqual('http://example.com/', f.clean('http://example.com')) |
| 638 | 655 | self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 20 characters (it has 38).'", f.clean, 'http://abcdefghijklmnopqrstuvwxyz.com') |
diff --git a/tests/regressiontests/forms/tests/forms.py b/tests/regressiontests/forms/tests/forms.py
index a8a28ba..a34fbcd 100644
|
a
|
b
|
class FormsTestCase(TestCase):
|
| 248 | 248 | get_spam = BooleanField() |
| 249 | 249 | |
| 250 | 250 | f = SignupForm(auto_id=False) |
| 251 | | self.assertHTMLEqual(str(f['email']), '<input type="text" name="email" />') |
| | 251 | self.assertHTMLEqual(str(f['email']), '<input type="email" name="email" />') |
| 252 | 252 | self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" />') |
| 253 | 253 | |
| 254 | 254 | f = SignupForm({'email': 'test@example.com', 'get_spam': True}, auto_id=False) |
| 255 | | self.assertHTMLEqual(str(f['email']), '<input type="text" name="email" value="test@example.com" />') |
| | 255 | self.assertHTMLEqual(str(f['email']), '<input type="email" name="email" value="test@example.com" />') |
| 256 | 256 | self.assertHTMLEqual(str(f['get_spam']), '<input checked="checked" type="checkbox" name="get_spam" />') |
| 257 | 257 | |
| 258 | 258 | # 'True' or 'true' should be rendered without a value attribute |
| … |
… |
class FormsTestCase(TestCase):
|
| 1736 | 1736 | <option value="2">Yes</option> |
| 1737 | 1737 | <option value="3">No</option> |
| 1738 | 1738 | </select></li> |
| 1739 | | <li><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></li> |
| 1740 | | <li class="required error"><ul class="errorlist"><li>This field is required.</li></ul><label for="id_age">Age:</label> <input type="text" name="age" id="id_age" /></li>""") |
| | 1739 | <li><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" /></li> |
| | 1740 | <li class="required error"><ul class="errorlist"><li>This field is required.</li></ul><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" /></li>""") |
| 1741 | 1741 | |
| 1742 | 1742 | self.assertHTMLEqual(p.as_p(), """<ul class="errorlist"><li>This field is required.</li></ul> |
| 1743 | 1743 | <p class="required error"><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p> |
| … |
… |
class FormsTestCase(TestCase):
|
| 1746 | 1746 | <option value="2">Yes</option> |
| 1747 | 1747 | <option value="3">No</option> |
| 1748 | 1748 | </select></p> |
| 1749 | | <p><label for="id_email">Email:</label> <input type="text" name="email" id="id_email" /></p> |
| | 1749 | <p><label for="id_email">Email:</label> <input type="email" name="email" id="id_email" /></p> |
| 1750 | 1750 | <ul class="errorlist"><li>This field is required.</li></ul> |
| 1751 | | <p class="required error"><label for="id_age">Age:</label> <input type="text" name="age" id="id_age" /></p>""") |
| | 1751 | <p class="required error"><label for="id_age">Age:</label> <input type="number" name="age" id="id_age" /></p>""") |
| 1752 | 1752 | |
| 1753 | 1753 | self.assertHTMLEqual(p.as_table(), """<tr class="required error"><th><label for="id_name">Name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="name" id="id_name" /></td></tr> |
| 1754 | 1754 | <tr class="required"><th><label for="id_is_cool">Is cool:</label></th><td><select name="is_cool" id="id_is_cool"> |
| … |
… |
class FormsTestCase(TestCase):
|
| 1756 | 1756 | <option value="2">Yes</option> |
| 1757 | 1757 | <option value="3">No</option> |
| 1758 | 1758 | </select></td></tr> |
| 1759 | | <tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email" /></td></tr> |
| 1760 | | <tr class="required error"><th><label for="id_age">Age:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="age" id="id_age" /></td></tr>""") |
| | 1759 | <tr><th><label for="id_email">Email:</label></th><td><input type="email" name="email" id="id_email" /></td></tr> |
| | 1760 | <tr class="required error"><th><label for="id_age">Age:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="number" name="age" id="id_age" /></td></tr>""") |
| 1761 | 1761 | |
| 1762 | 1762 | def test_label_split_datetime_not_displayed(self): |
| 1763 | 1763 | class EventForm(Form): |
diff --git a/tests/regressiontests/forms/tests/formsets.py b/tests/regressiontests/forms/tests/formsets.py
index 3decd1f..79f3f2f 100644
|
a
|
b
|
class FormsFormsetTestCase(TestCase):
|
| 51 | 51 | formset = ChoiceFormSet(auto_id=False, prefix='choices') |
| 52 | 52 | self.assertHTMLEqual(str(formset), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" /> |
| 53 | 53 | <tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr> |
| 54 | | <tr><th>Votes:</th><td><input type="text" name="choices-0-votes" /></td></tr>""") |
| | 54 | <tr><th>Votes:</th><td><input type="number" name="choices-0-votes" /></td></tr>""") |
| 55 | 55 | |
| 56 | 56 | # On thing to note is that there needs to be a special value in the data. This |
| 57 | 57 | # value tells the FormSet how many forms were displayed so it can tell how |
| … |
… |
class FormsFormsetTestCase(TestCase):
|
| 135 | 135 | form_output.append(form.as_ul()) |
| 136 | 136 | |
| 137 | 137 | self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
| 138 | | <li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
| | 138 | <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> |
| 139 | 139 | <li>Choice: <input type="text" name="choices-1-choice" /></li> |
| 140 | | <li>Votes: <input type="text" name="choices-1-votes" /></li>""") |
| | 140 | <li>Votes: <input type="number" name="choices-1-votes" /></li>""") |
| 141 | 141 | |
| 142 | 142 | # Let's simulate what would happen if we submitted this form. |
| 143 | 143 | |
| … |
… |
class FormsFormsetTestCase(TestCase):
|
| 208 | 208 | form_output.append(form.as_ul()) |
| 209 | 209 | |
| 210 | 210 | self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" /></li> |
| 211 | | <li>Votes: <input type="text" name="choices-0-votes" /></li> |
| | 211 | <li>Votes: <input type="number" name="choices-0-votes" /></li> |
| 212 | 212 | <li>Choice: <input type="text" name="choices-1-choice" /></li> |
| 213 | | <li>Votes: <input type="text" name="choices-1-votes" /></li> |
| | 213 | <li>Votes: <input type="number" name="choices-1-votes" /></li> |
| 214 | 214 | <li>Choice: <input type="text" name="choices-2-choice" /></li> |
| 215 | | <li>Votes: <input type="text" name="choices-2-votes" /></li>""") |
| | 215 | <li>Votes: <input type="number" name="choices-2-votes" /></li>""") |
| 216 | 216 | |
| 217 | 217 | # Since we displayed every form as blank, we will also accept them back as blank. |
| 218 | 218 | # This may seem a little strange, but later we will show how to require a minimum |
| … |
… |
class FormsFormsetTestCase(TestCase):
|
| 299 | 299 | form_output.append(form.as_ul()) |
| 300 | 300 | |
| 301 | 301 | self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
| 302 | | <li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
| | 302 | <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> |
| 303 | 303 | <li>Choice: <input type="text" name="choices-1-choice" /></li> |
| 304 | | <li>Votes: <input type="text" name="choices-1-votes" /></li> |
| | 304 | <li>Votes: <input type="number" name="choices-1-votes" /></li> |
| 305 | 305 | <li>Choice: <input type="text" name="choices-2-choice" /></li> |
| 306 | | <li>Votes: <input type="text" name="choices-2-votes" /></li> |
| | 306 | <li>Votes: <input type="number" name="choices-2-votes" /></li> |
| 307 | 307 | <li>Choice: <input type="text" name="choices-3-choice" /></li> |
| 308 | | <li>Votes: <input type="text" name="choices-3-votes" /></li>""") |
| | 308 | <li>Votes: <input type="number" name="choices-3-votes" /></li>""") |
| 309 | 309 | |
| 310 | 310 | # Make sure retrieving an empty form works, and it shows up in the form list |
| 311 | 311 | |
| 312 | 312 | self.assertTrue(formset.empty_form.empty_permitted) |
| 313 | 313 | self.assertHTMLEqual(formset.empty_form.as_ul(), """<li>Choice: <input type="text" name="choices-__prefix__-choice" /></li> |
| 314 | | <li>Votes: <input type="text" name="choices-__prefix__-votes" /></li>""") |
| | 314 | <li>Votes: <input type="number" name="choices-__prefix__-votes" /></li>""") |
| 315 | 315 | |
| 316 | 316 | def test_formset_with_deletion(self): |
| 317 | 317 | # FormSets with deletion ###################################################### |
| … |
… |
class FormsFormsetTestCase(TestCase):
|
| 329 | 329 | form_output.append(form.as_ul()) |
| 330 | 330 | |
| 331 | 331 | self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
| 332 | | <li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
| | 332 | <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> |
| 333 | 333 | <li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li> |
| 334 | 334 | <li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li> |
| 335 | | <li>Votes: <input type="text" name="choices-1-votes" value="900" /></li> |
| | 335 | <li>Votes: <input type="number" name="choices-1-votes" value="900" /></li> |
| 336 | 336 | <li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li> |
| 337 | 337 | <li>Choice: <input type="text" name="choices-2-choice" /></li> |
| 338 | | <li>Votes: <input type="text" name="choices-2-votes" /></li> |
| | 338 | <li>Votes: <input type="number" name="choices-2-votes" /></li> |
| 339 | 339 | <li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li>""") |
| 340 | 340 | |
| 341 | 341 | # To delete something, we just need to set that form's special delete field to |
| … |
… |
class FormsFormsetTestCase(TestCase):
|
| 426 | 426 | form_output.append(form.as_ul()) |
| 427 | 427 | |
| 428 | 428 | self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
| 429 | | <li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
| 430 | | <li>Order: <input type="text" name="choices-0-ORDER" value="1" /></li> |
| | 429 | <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> |
| | 430 | <li>Order: <input type="number" name="choices-0-ORDER" value="1" /></li> |
| 431 | 431 | <li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li> |
| 432 | | <li>Votes: <input type="text" name="choices-1-votes" value="900" /></li> |
| 433 | | <li>Order: <input type="text" name="choices-1-ORDER" value="2" /></li> |
| | 432 | <li>Votes: <input type="number" name="choices-1-votes" value="900" /></li> |
| | 433 | <li>Order: <input type="number" name="choices-1-ORDER" value="2" /></li> |
| 434 | 434 | <li>Choice: <input type="text" name="choices-2-choice" /></li> |
| 435 | | <li>Votes: <input type="text" name="choices-2-votes" /></li> |
| 436 | | <li>Order: <input type="text" name="choices-2-ORDER" /></li>""") |
| | 435 | <li>Votes: <input type="number" name="choices-2-votes" /></li> |
| | 436 | <li>Order: <input type="number" name="choices-2-ORDER" /></li>""") |
| 437 | 437 | |
| 438 | 438 | data = { |
| 439 | 439 | 'choices-TOTAL_FORMS': '3', # the number of forms rendered |
| … |
… |
class FormsFormsetTestCase(TestCase):
|
| 537 | 537 | form_output.append(form.as_ul()) |
| 538 | 538 | |
| 539 | 539 | self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
| 540 | | <li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
| 541 | | <li>Order: <input type="text" name="choices-0-ORDER" value="1" /></li> |
| | 540 | <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li> |
| | 541 | <li>Order: <input type="number" name="choices-0-ORDER" value="1" /></li> |
| 542 | 542 | <li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li> |
| 543 | 543 | <li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li> |
| 544 | | <li>Votes: <input type="text" name="choices-1-votes" value="900" /></li> |
| 545 | | <li>Order: <input type="text" name="choices-1-ORDER" value="2" /></li> |
| | 544 | <li>Votes: <input type="number" name="choices-1-votes" value="900" /></li> |
| | 545 | <li>Order: <input type="number" name="choices-1-ORDER" value="2" /></li> |
| 546 | 546 | <li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li> |
| 547 | 547 | <li>Choice: <input type="text" name="choices-2-choice" value="The Decemberists" /></li> |
| 548 | | <li>Votes: <input type="text" name="choices-2-votes" value="500" /></li> |
| 549 | | <li>Order: <input type="text" name="choices-2-ORDER" value="3" /></li> |
| | 548 | <li>Votes: <input type="number" name="choices-2-votes" value="500" /></li> |
| | 549 | <li>Order: <input type="number" name="choices-2-ORDER" value="3" /></li> |
| 550 | 550 | <li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li> |
| 551 | 551 | <li>Choice: <input type="text" name="choices-3-choice" /></li> |
| 552 | | <li>Votes: <input type="text" name="choices-3-votes" /></li> |
| 553 | | <li>Order: <input type="text" name="choices-3-ORDER" /></li> |
| | 552 | <li>Votes: <input type="number" name="choices-3-votes" /></li> |
| | 553 | <li>Order: <input type="number" name="choices-3-ORDER" /></li> |
| 554 | 554 | <li>Delete: <input type="checkbox" name="choices-3-DELETE" /></li>""") |
| 555 | 555 | |
| 556 | 556 | # Let's delete Fergie, and put The Decemberists ahead of Calexico. |
| … |
… |
class FormsetAsFooTests(TestCase):
|
| 866 | 866 | formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
| 867 | 867 | self.assertHTMLEqual(formset.as_table(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /> |
| 868 | 868 | <tr><th>Choice:</th><td><input type="text" name="choices-0-choice" value="Calexico" /></td></tr> |
| 869 | | <tr><th>Votes:</th><td><input type="text" name="choices-0-votes" value="100" /></td></tr>""") |
| | 869 | <tr><th>Votes:</th><td><input type="number" name="choices-0-votes" value="100" /></td></tr>""") |
| 870 | 870 | |
| 871 | 871 | def test_as_p(self): |
| 872 | 872 | formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
| 873 | 873 | self.assertHTMLEqual(formset.as_p(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /> |
| 874 | 874 | <p>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></p> |
| 875 | | <p>Votes: <input type="text" name="choices-0-votes" value="100" /></p>""") |
| | 875 | <p>Votes: <input type="number" name="choices-0-votes" value="100" /></p>""") |
| 876 | 876 | |
| 877 | 877 | def test_as_ul(self): |
| 878 | 878 | formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
| 879 | 879 | self.assertHTMLEqual(formset.as_ul(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /> |
| 880 | 880 | <li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
| 881 | | <li>Votes: <input type="text" name="choices-0-votes" value="100" /></li>""") |
| | 881 | <li>Votes: <input type="number" name="choices-0-votes" value="100" /></li>""") |
| 882 | 882 | |
| 883 | 883 | |
| 884 | 884 | # Regression test for #11418 ################################################# |
diff --git a/tests/regressiontests/generic_inline_admin/tests.py b/tests/regressiontests/generic_inline_admin/tests.py
index fea30b4..f03641d 100644
|
a
|
b
|
class GenericAdminViewTest(TestCase):
|
| 102 | 102 | # Works with no queryset |
| 103 | 103 | formset = EpisodeMediaFormSet(instance=e) |
| 104 | 104 | self.assertEqual(len(formset.forms), 5) |
| 105 | | self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.mp3_media_pk) |
| 106 | | self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>' % self.png_media_pk) |
| 107 | | self.assertHTMLEqual(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="text" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>') |
| | 105 | self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="url" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.mp3_media_pk) |
| | 106 | self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="url" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>' % self.png_media_pk) |
| | 107 | self.assertHTMLEqual(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="url" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>') |
| 108 | 108 | |
| 109 | 109 | # A queryset can be used to alter display ordering |
| 110 | 110 | formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url')) |
| 111 | 111 | self.assertEqual(len(formset.forms), 5) |
| 112 | | self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.png_media_pk) |
| 113 | | self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>' % self.mp3_media_pk) |
| 114 | | self.assertHTMLEqual(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="text" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>') |
| | 112 | self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="url" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.png_media_pk) |
| | 113 | self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="url" name="generic_inline_admin-media-content_type-object_id-1-url" value="http://example.com/podcast.mp3" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>' % self.mp3_media_pk) |
| | 114 | self.assertHTMLEqual(formset.forms[2].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-2-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-2-url" type="url" name="generic_inline_admin-media-content_type-object_id-2-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-2-id" id="id_generic_inline_admin-media-content_type-object_id-2-id" /></p>') |
| 115 | 115 | |
| 116 | 116 | # Works with a queryset that omits items |
| 117 | 117 | formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png")) |
| 118 | 118 | self.assertEqual(len(formset.forms), 4) |
| 119 | | self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="text" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.png_media_pk) |
| 120 | | self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="text" name="generic_inline_admin-media-content_type-object_id-1-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>') |
| | 119 | self.assertHTMLEqual(formset.forms[0].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-0-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-0-url" type="url" name="generic_inline_admin-media-content_type-object_id-0-url" value="http://example.com/logo.png" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-0-id" value="%s" id="id_generic_inline_admin-media-content_type-object_id-0-id" /></p>' % self.png_media_pk) |
| | 120 | self.assertHTMLEqual(formset.forms[1].as_p(), '<p><label for="id_generic_inline_admin-media-content_type-object_id-1-url">Url:</label> <input id="id_generic_inline_admin-media-content_type-object_id-1-url" type="url" name="generic_inline_admin-media-content_type-object_id-1-url" maxlength="200" /><input type="hidden" name="generic_inline_admin-media-content_type-object_id-1-id" id="id_generic_inline_admin-media-content_type-object_id-1-id" /></p>') |
| 121 | 121 | |
| 122 | 122 | def testGenericInlineFormsetFactory(self): |
| 123 | 123 | # Regression test for #10522. |
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
index bce3d61..60e234e 100644
|
a
|
b
|
class FormattingTests(TestCase):
|
| 634 | 634 | self.assertEqual(True, form6.is_valid()) |
| 635 | 635 | self.assertHTMLEqual( |
| 636 | 636 | form6.as_ul(), |
| 637 | | '<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" value="acme" maxlength="50" /></li>\n<li><label for="id_date_added">Date added:</label> <input type="text" name="date_added" value="31.12.2009 06:00:00" id="id_date_added" /></li>\n<li><label for="id_cents_paid">Cents paid:</label> <input type="text" name="cents_paid" value="59,47" id="id_cents_paid" /></li>\n<li><label for="id_products_delivered">Products delivered:</label> <input type="text" name="products_delivered" value="12000" id="id_products_delivered" /></li>' |
| | 637 | '<li><label for="id_name">Name:</label> <input id="id_name" type="text" name="name" value="acme" maxlength="50" /></li>\n<li><label for="id_date_added">Date added:</label> <input type="text" name="date_added" value="31.12.2009 06:00:00" id="id_date_added" /></li>\n<li><label for="id_cents_paid">Cents paid:</label> <input type="number" name="cents_paid" value="59,47" maxlength="5" step="0.01" id="id_cents_paid" /></li>\n<li><label for="id_products_delivered">Products delivered:</label> <input type="number" name="products_delivered" value="12000" id="id_products_delivered" /></li>' |
| 638 | 638 | ) |
| 639 | 639 | self.assertEqual(localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), '31.12.2009 06:00:00') |
| 640 | 640 | self.assertEqual(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added']) |
| 641 | 641 | with self.settings(USE_THOUSAND_SEPARATOR=True): |
| 642 | 642 | # Checking for the localized "products_delivered" field |
| 643 | | self.assertTrue('<input type="text" name="products_delivered" value="12.000" id="id_products_delivered" />' in form6.as_ul()) |
| | 643 | self.assertTrue('<input type="number" name="products_delivered" value="12.000" id="id_products_delivered" />' in form6.as_ul()) |
| 644 | 644 | |
| 645 | 645 | def test_iter_format_modules(self): |
| 646 | 646 | """ |