Ticket #16630: html5-input-types-take5.patch

File html5-input-types-take5.patch, 52.8 KB (added by Stephen Burrows, 12 years ago)

Updated patch to current master.

  • django/forms/fields.py

    diff --git a/django/forms/fields.py b/django/forms/fields.py
    index 4438812..940374b 100644
    a b from io import BytesIO  
    1818from django.core import validators
    1919from django.core.exceptions import ValidationError
    2020from django.forms.util import ErrorList, from_current_timezone, to_current_timezone
    21 from django.forms.widgets import (TextInput, PasswordInput, HiddenInput,
     21from django.forms.widgets import (
     22    TextInput, NumberInput, PasswordInput, EmailInput, URLInput, HiddenInput,
    2223    MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select,
    2324    NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput,
    24     SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION)
     25    SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION
     26)
    2527from django.utils import formats
    2628from django.utils.encoding import smart_text, force_text
    2729from django.utils.ipv6 import clean_ipv6_address
    class CharField(Field):  
    205207        return attrs
    206208
    207209class IntegerField(Field):
     210    widget = NumberInput
    208211    default_error_messages = {
    209212        'invalid': _('Enter a whole number.'),
    210213        'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'),
    class IntegerField(Field):  
    236239            raise ValidationError(self.error_messages['invalid'])
    237240        return value
    238241
     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
    239251class FloatField(IntegerField):
    240252    default_error_messages = {
    241253        'invalid': _('Enter a number.'),
    class FloatField(IntegerField):  
    257269            raise ValidationError(self.error_messages['invalid'])
    258270        return value
    259271
    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
     278class DecimalField(IntegerField):
    261279    default_error_messages = {
    262280        '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.'),
    265281        'max_digits': _('Ensure that there are no more than %s digits in total.'),
    266282        'max_decimal_places': _('Ensure that there are no more than %s decimal places.'),
    267283        'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.')
    268284    }
    269285
    270286    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
    272287        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)
    279289
    280290    def to_python(self, value):
    281291        """
    class DecimalField(Field):  
    324334            raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places))
    325335        return value
    326336
     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
    327346class BaseTemporalField(Field):
    328347
    329348    def __init__(self, input_formats=None, *args, **kwargs):
    class RegexField(CharField):  
    460479    regex = property(_get_regex, _set_regex)
    461480
    462481class EmailField(CharField):
     482    widget = EmailInput
    463483    default_error_messages = {
    464484        'invalid': _('Enter a valid email address.'),
    465485    }
    class ImageField(FileField):  
    576596        return f
    577597
    578598class URLField(CharField):
     599    widget = URLInput
    579600    default_error_messages = {
    580601        'invalid': _('Enter a valid URL.'),
    581602    }
  • django/forms/widgets.py

    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  
    2222from django.utils import datetime_safe, formats, six
    2323
    2424__all__ = (
    25     'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'PasswordInput',
     25    'Media', 'MediaDefiningClass', 'Widget', 'TextInput',
     26    'EmailInput', 'URLInput', 'NumberInput', 'PasswordInput',
    2627    'HiddenInput', 'MultipleHiddenInput', 'ClearableFileInput',
    2728    'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput',
    2829    'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
    class TextInput(Input):  
    270271        super(TextInput, self).__init__(attrs)
    271272
    272273
     274class NumberInput(TextInput):
     275    input_type = 'number'
     276
     277
     278class EmailInput(TextInput):
     279    input_type = 'email'
     280
     281
     282class URLInput(TextInput):
     283    input_type = 'url'
     284
     285
    273286class PasswordInput(TextInput):
    274287    input_type = 'password'
    275288
  • docs/ref/forms/fields.txt

    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::  
    112112    >>> f = CommentForm(auto_id=False)
    113113    >>> print(f)
    114114    <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>
    116116    <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
    117117
    118118``initial``
    field is initialized to a particular value. For example::  
    135135    >>> f = CommentForm(auto_id=False)
    136136    >>> print(f)
    137137    <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>
    139139    <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
    140140
    141141You may be thinking, why not just pass a dictionary of the initial values as
    and the HTML output will include any validation errors::  
    150150    >>> f = CommentForm(default_data, auto_id=False)
    151151    >>> print(f)
    152152    <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>
    154154    <tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" /></td></tr>
    155155
    156156This is why ``initial`` values are only displayed for unbound forms. For bound
    fields. We've specified ``auto_id=False`` to simplify the output::  
    217217    >>> print(f.as_ul()))
    218218    <li>Subject: <input type="text" name="subject" maxlength="100" /> <span class="helptext">100 characters max.</span></li>
    219219    <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>
    221221    <li>Cc myself: <input type="checkbox" name="cc_myself" /></li>
    222222    >>> print(f.as_p())
    223223    <p>Subject: <input type="text" name="subject" maxlength="100" /> <span class="helptext">100 characters max.</span></p>
    224224    <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>
    226226    <p>Cc myself: <input type="checkbox" name="cc_myself" /></p>
    227227
    228228``error_messages``
    For each field, we describe the default widget used if you don't specify  
    450450
    451451.. class:: DecimalField(**kwargs)
    452452
    453     * Default widget: ``TextInput``
     453    * Default widget: ``NumberInput``
    454454    * Empty value: ``None``
    455455    * Normalizes to: A Python ``decimal``.
    456456    * 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  
    485485
    486486.. class:: EmailField(**kwargs)
    487487
    488     * Default widget: ``TextInput``
     488    * Default widget: ``EmailInput``
    489489    * Empty value: ``''`` (an empty string)
    490490    * Normalizes to: A Unicode object.
    491491    * 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  
    576576
    577577.. class:: FloatField(**kwargs)
    578578
    579     * Default widget: ``TextInput``
     579    * Default widget: ``NumberInput``
    580580    * Empty value: ``None``
    581581    * Normalizes to: A Python float.
    582582    * 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  
    617617
    618618.. class:: IntegerField(**kwargs)
    619619
    620     * Default widget: ``TextInput``
     620    * Default widget: ``NumberInput``
    621621    * Empty value: ``None``
    622622    * Normalizes to: A Python integer or long integer.
    623623    * 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  
    803803
    804804.. class:: URLField(**kwargs)
    805805
    806     * Default widget: ``TextInput``
     806    * Default widget: ``URLInput``
    807807    * Empty value: ``''`` (an empty string)
    808808    * Normalizes to: A Unicode object.
    809809    * Validates that the given value is a valid URL.
  • docs/ref/forms/widgets.txt

    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::  
    139139    >>> f = CommentForm(auto_id=False)
    140140    >>> f.as_table()
    141141    <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>
    143143    <tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
    144144
    145145On 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:  
    160160    >>> f = CommentForm(auto_id=False)
    161161    >>> f.as_table()
    162162    <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>
    164164    <tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
    165165
    166166.. _styling-widget-classes:
    These widgets make use of the HTML elements ``input`` and ``textarea``.  
    280280
    281281    Text input: ``<input type='text' ...>``
    282282
     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
    283310``PasswordInput``
    284311~~~~~~~~~~~~~~~~~
    285312
  • docs/releases/1.5.txt

    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:  
    184184  look up permissions by using ``{% if 'someapp.someperm' in perms %}``
    185185  in templates.
    186186
     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
    187193Backwards incompatible changes in 1.5
    188194=====================================
    189195
  • tests/modeltests/model_forms/tests.py

    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):  
    10881088<option value="%s">Joe Better</option>
    10891089<option value="%s">Mike Royko</option>
    10901090</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))
    10921092
    10931093        data = {
    10941094            'writer': six.text_type(w_woodward.pk),
    class OldFormForXTests(TestCase):  
    11061106<option value="%s">Joe Better</option>
    11071107<option value="%s">Mike Royko</option>
    11081108</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))
    11101110
    11111111    def test_phone_number_field(self):
    11121112        f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'})
  • tests/modeltests/model_formsets/tests.py

    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):  
    384384        self.assertEqual(len(formset.forms), 1)
    385385        self.assertHTMLEqual(formset.forms[0].as_p(),
    386386            '<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>')
    388388
    389389        data = {
    390390            'form-TOTAL_FORMS': '1', # the number of forms rendered
    class ModelFormsetTest(TestCase):  
    407407        self.assertEqual(len(formset.forms), 2)
    408408        self.assertHTMLEqual(formset.forms[0].as_p(),
    409409            '<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)
    411411        self.assertHTMLEqual(formset.forms[1].as_p(),
    412412            '<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>')
    414414
    415415        data = {
    416416            'form-TOTAL_FORMS': '2', # the number of forms rendered
    class ModelFormsetTest(TestCase):  
    550550        formset = AuthorBooksFormSet2(instance=author)
    551551        self.assertEqual(len(formset.forms), 1)
    552552        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'
    554554            '<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>')
    555555
    556556        data = {
    class ModelFormsetTest(TestCase):  
    798798            '<option value="%d">Joe Perry at Giordanos</option>\n'
    799799            '<option value="%d">Jack Berry at Giordanos</option>\n'
    800800            '</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>'
    802802            % (owner1.auto_id, owner2.auto_id))
    803803
    804804        owner1 = Owner.objects.get(name='Joe Perry')
    class ModelFormsetTest(TestCase):  
    808808        formset = FormSet(instance=owner1)
    809809        self.assertEqual(len(formset.forms), 1)
    810810        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>'
    812812            % owner1.auto_id)
    813813
    814814        data = {
    class ModelFormsetTest(TestCase):  
    829829        formset = FormSet(instance=owner1)
    830830        self.assertEqual(len(formset.forms), 1)
    831831        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>'
    833833            % owner1.auto_id)
    834834
    835835        data = {
    class ModelFormsetTest(TestCase):  
    985985        result = re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)?', '__DATETIME__', result)
    986986        self.assertHTMLEqual(result,
    987987            '<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>'
    989989            % person.id)
    990990
    991991        # test for validation with callable defaults. Validations rely on hidden fields
  • tests/regressiontests/forms/tests/extra.py

    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):  
    614614        f = CommentForm(data, auto_id=False, error_class=DivErrorList)
    615615        self.assertHTMLEqual(f.as_p(), """<p>Name: <input type="text" name="name" maxlength="50" /></p>
    616616<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>
    618618<div class="errorlist"><div class="error">This field is required.</div></div>
    619619<p>Comment: <input type="text" name="comment" /></p>""")
    620620
  • tests/regressiontests/forms/tests/fields.py

    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):  
    5151
    5252class FieldsTests(SimpleTestCase):
    5353
     54    def assertWidgetRendersTo(self, field, to):
     55        class _Form(Form):
     56            f = field
     57        self.assertEqual(str(_Form()['f']), to)
     58
    5459    def test_field_sets_widget_is_required(self):
    5560        self.assertTrue(Field(required=True).widget.is_required)
    5661        self.assertFalse(Field(required=False).widget.is_required)
    class FieldsTests(SimpleTestCase):  
    124129
    125130    def test_integerfield_1(self):
    126131        f = IntegerField()
     132        self.assertWidgetRendersTo(f, '<input type="number" name="f" id="id_f" />')
    127133        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
    128134        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
    129135        self.assertEqual(1, f.clean('1'))
    class FieldsTests(SimpleTestCase):  
    158164
    159165    def test_integerfield_3(self):
    160166        f = IntegerField(max_value=10)
     167        self.assertWidgetRendersTo(f, '<input max="10" type="number" name="f" id="id_f" />')
    161168        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
    162169        self.assertEqual(1, f.clean(1))
    163170        self.assertEqual(10, f.clean(10))
    class FieldsTests(SimpleTestCase):  
    169176
    170177    def test_integerfield_4(self):
    171178        f = IntegerField(min_value=10)
     179        self.assertWidgetRendersTo(f, '<input id="id_f" type="number" name="f" min="10" />')
    172180        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
    173181        self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 10.'", f.clean, 1)
    174182        self.assertEqual(10, f.clean(10))
    class FieldsTests(SimpleTestCase):  
    180188
    181189    def test_integerfield_5(self):
    182190        f = IntegerField(min_value=10, max_value=20)
     191        self.assertWidgetRendersTo(f, '<input id="id_f" max="20" type="number" name="f" min="10" />')
    183192        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
    184193        self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 10.'", f.clean, 1)
    185194        self.assertEqual(10, f.clean(10))
    class FieldsTests(SimpleTestCase):  
    195204
    196205    def test_floatfield_1(self):
    197206        f = FloatField()
     207        self.assertWidgetRendersTo(f, '<input step="any" type="number" name="f" id="id_f" />')
    198208        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
    199209        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
    200210        self.assertEqual(1.0, f.clean('1'))
    class FieldsTests(SimpleTestCase):  
    221231
    222232    def test_floatfield_3(self):
    223233        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" />')
    224235        self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'", f.clean, '1.6')
    225236        self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'", f.clean, '0.4')
    226237        self.assertEqual(1.5, f.clean('1.5'))
    class FieldsTests(SimpleTestCase):  
    232243
    233244    def test_decimalfield_1(self):
    234245        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" />')
    235247        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
    236248        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
    237249        self.assertEqual(f.clean('1'), Decimal("1"))
    class FieldsTests(SimpleTestCase):  
    277289
    278290    def test_decimalfield_3(self):
    279291        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" />')
    280293        self.assertRaisesMessage(ValidationError, "'Ensure this value is less than or equal to 1.5.'", f.clean, '1.6')
    281294        self.assertRaisesMessage(ValidationError, "'Ensure this value is greater than or equal to 0.5.'", f.clean, '0.4')
    282295        self.assertEqual(f.clean('1.5'), Decimal("1.5"))
    class FieldsTests(SimpleTestCase):  
    504517
    505518    def test_emailfield_1(self):
    506519        f = EmailField()
     520        self.assertWidgetRendersTo(f, '<input type="email" name="f" id="id_f" />')
    507521        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
    508522        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
    509523        self.assertEqual('person@example.com', f.clean('person@example.com'))
    class FieldsTests(SimpleTestCase):  
    542556
    543557    def test_emailfield_3(self):
    544558        f = EmailField(min_length=10, max_length=15)
     559        self.assertWidgetRendersTo(f, '<input id="id_f" type="email" name="f" maxlength="15" />')
    545560        self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 10 characters (it has 9).'", f.clean, 'a@foo.com')
    546561        self.assertEqual('alf@foo.com', f.clean('alf@foo.com'))
    547562        self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 15 characters (it has 20).'", f.clean, 'alf123456788@foo.com')
    class FieldsTests(SimpleTestCase):  
    582597
    583598    def test_urlfield_1(self):
    584599        f = URLField()
     600        self.assertWidgetRendersTo(f, '<input type="url" name="f" id="id_f" />')
    585601        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
    586602        self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
    587603        self.assertEqual('http://localhost/', f.clean('http://localhost'))
    class FieldsTests(SimpleTestCase):  
    633649
    634650    def test_urlfield_5(self):
    635651        f = URLField(min_length=15, max_length=20)
     652        self.assertWidgetRendersTo(f, '<input id="id_f" type="url" name="f" maxlength="20" />')
    636653        self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 15 characters (it has 13).'", f.clean, 'http://f.com')
    637654        self.assertEqual('http://example.com/', f.clean('http://example.com'))
    638655        self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 20 characters (it has 38).'", f.clean, 'http://abcdefghijklmnopqrstuvwxyz.com')
  • tests/regressiontests/forms/tests/forms.py

    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):  
    248248            get_spam = BooleanField()
    249249
    250250        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" />')
    252252        self.assertHTMLEqual(str(f['get_spam']), '<input type="checkbox" name="get_spam" />')
    253253
    254254        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" />')
    256256        self.assertHTMLEqual(str(f['get_spam']), '<input checked="checked" type="checkbox" name="get_spam" />')
    257257
    258258        # 'True' or 'true' should be rendered without a value attribute
    class FormsTestCase(TestCase):  
    17361736<option value="2">Yes</option>
    17371737<option value="3">No</option>
    17381738</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>""")
    17411741
    17421742        self.assertHTMLEqual(p.as_p(), """<ul class="errorlist"><li>This field is required.</li></ul>
    17431743<p class="required error"><label for="id_name">Name:</label> <input type="text" name="name" id="id_name" /></p>
    class FormsTestCase(TestCase):  
    17461746<option value="2">Yes</option>
    17471747<option value="3">No</option>
    17481748</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>
    17501750<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>""")
    17521752
    17531753        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>
    17541754<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):  
    17561756<option value="2">Yes</option>
    17571757<option value="3">No</option>
    17581758</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>""")
    17611761
    17621762    def test_label_split_datetime_not_displayed(self):
    17631763        class EventForm(Form):
  • tests/regressiontests/forms/tests/formsets.py

    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):  
    5151        formset = ChoiceFormSet(auto_id=False, prefix='choices')
    5252        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" />
    5353<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>""")
    5555
    5656        # On thing to note is that there needs to be a special value in the data. This
    5757        # value tells the FormSet how many forms were displayed so it can tell how
    class FormsFormsetTestCase(TestCase):  
    135135            form_output.append(form.as_ul())
    136136
    137137        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>
    139139<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>""")
    141141
    142142        # Let's simulate what would happen if we submitted this form.
    143143
    class FormsFormsetTestCase(TestCase):  
    208208            form_output.append(form.as_ul())
    209209
    210210        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>
    212212<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>
    214214<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>""")
    216216
    217217        # Since we displayed every form as blank, we will also accept them back as blank.
    218218        # This may seem a little strange, but later we will show how to require a minimum
    class FormsFormsetTestCase(TestCase):  
    299299            form_output.append(form.as_ul())
    300300
    301301        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>
    303303<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>
    305305<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>
    307307<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>""")
    309309
    310310        # Make sure retrieving an empty form works, and it shows up in the form list
    311311
    312312        self.assertTrue(formset.empty_form.empty_permitted)
    313313        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>""")
    315315
    316316    def test_formset_with_deletion(self):
    317317        # FormSets with deletion ######################################################
    class FormsFormsetTestCase(TestCase):  
    329329            form_output.append(form.as_ul())
    330330
    331331        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>
    333333<li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li>
    334334<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>
    336336<li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li>
    337337<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>
    339339<li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li>""")
    340340
    341341        # To delete something, we just need to set that form's special delete field to
    class FormsFormsetTestCase(TestCase):  
    426426            form_output.append(form.as_ul())
    427427
    428428        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>
    431431<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>
    434434<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>""")
    437437
    438438        data = {
    439439            'choices-TOTAL_FORMS': '3', # the number of forms rendered
    class FormsFormsetTestCase(TestCase):  
    537537            form_output.append(form.as_ul())
    538538
    539539        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>
    542542<li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li>
    543543<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>
    546546<li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li>
    547547<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>
    550550<li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li>
    551551<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>
    554554<li>Delete: <input type="checkbox" name="choices-3-DELETE" /></li>""")
    555555
    556556        # Let's delete Fergie, and put The Decemberists ahead of Calexico.
    class FormsetAsFooTests(TestCase):  
    866866        formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
    867867        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" />
    868868<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>""")
    870870
    871871    def test_as_p(self):
    872872        formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
    873873        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" />
    874874<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>""")
    876876
    877877    def test_as_ul(self):
    878878        formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
    879879        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" />
    880880<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>""")
    882882
    883883
    884884# Regression test for #11418 #################################################
  • tests/regressiontests/generic_inline_admin/tests.py

    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):  
    102102        # Works with no queryset
    103103        formset = EpisodeMediaFormSet(instance=e)
    104104        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>')
    108108
    109109        # A queryset can be used to alter display ordering
    110110        formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url'))
    111111        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>')
    115115
    116116        # Works with a queryset that omits items
    117117        formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png"))
    118118        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>')
    121121
    122122    def testGenericInlineFormsetFactory(self):
    123123        # Regression test for #10522.
  • tests/regressiontests/i18n/tests.py

    diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py
    index bce3d61..60e234e 100644
    a b class FormattingTests(TestCase):  
    634634            self.assertEqual(True, form6.is_valid())
    635635            self.assertHTMLEqual(
    636636                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>'
    638638            )
    639639            self.assertEqual(localize_input(datetime.datetime(2009, 12, 31, 6, 0, 0)), '31.12.2009 06:00:00')
    640640            self.assertEqual(datetime.datetime(2009, 12, 31, 6, 0, 0), form6.cleaned_data['date_added'])
    641641            with self.settings(USE_THOUSAND_SEPARATOR=True):
    642642                # 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())
    644644
    645645    def test_iter_format_modules(self):
    646646        """
Back to Top