Code

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

File html5-input-types-take5.patch, 52.8 KB (added by melinath, 19 months 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        """