parent
4f16376274
commit
f7394d2c32
|
@ -19,7 +19,7 @@ from django.core import validators
|
|||
from django.core.exceptions import ValidationError
|
||||
from django.forms.util import ErrorList, from_current_timezone, to_current_timezone
|
||||
from django.forms.widgets import (
|
||||
TextInput, PasswordInput, EmailInput, HiddenInput,
|
||||
TextInput, PasswordInput, EmailInput, URLInput, HiddenInput,
|
||||
MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select,
|
||||
NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput,
|
||||
SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION
|
||||
|
@ -612,6 +612,7 @@ class ImageField(FileField):
|
|||
return f
|
||||
|
||||
class URLField(CharField):
|
||||
widget = URLInput
|
||||
default_error_messages = {
|
||||
'invalid': _('Enter a valid URL.'),
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ from django.utils.safestring import mark_safe
|
|||
from django.utils import datetime_safe, formats, six
|
||||
|
||||
__all__ = (
|
||||
'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'EmailInput', 'PasswordInput',
|
||||
'Media', 'MediaDefiningClass', 'Widget', 'TextInput',
|
||||
'EmailInput', 'URLInput', 'PasswordInput',
|
||||
'HiddenInput', 'MultipleHiddenInput', 'ClearableFileInput',
|
||||
'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput',
|
||||
'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
|
||||
|
@ -255,6 +256,10 @@ class EmailInput(TextInput):
|
|||
input_type = 'email'
|
||||
|
||||
|
||||
class URLInput(TextInput):
|
||||
input_type = 'url'
|
||||
|
||||
|
||||
class PasswordInput(TextInput):
|
||||
input_type = 'password'
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ precedence::
|
|||
>>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
|
||||
>>> print(f)
|
||||
<tr><th>Name:</th><td><input type="text" name="name" value="instance" /></td></tr>
|
||||
<tr><th>Url:</th><td><input type="text" name="url" /></td></tr>
|
||||
<tr><th>Url:</th><td><input type="url" name="url" /></td></tr>
|
||||
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
|
||||
|
||||
Accessing "clean" data
|
||||
|
|
|
@ -112,7 +112,7 @@ We've specified ``auto_id=False`` to simplify the output::
|
|||
>>> f = CommentForm(auto_id=False)
|
||||
>>> print(f)
|
||||
<tr><th>Your name:</th><td><input type="text" name="name" /></td></tr>
|
||||
<tr><th>Your Web site:</th><td><input type="text" name="url" /></td></tr>
|
||||
<tr><th>Your Web site:</th><td><input type="url" name="url" /></td></tr>
|
||||
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
|
||||
|
||||
``initial``
|
||||
|
@ -135,7 +135,7 @@ field is initialized to a particular value. For example::
|
|||
>>> f = CommentForm(auto_id=False)
|
||||
>>> print(f)
|
||||
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
|
||||
<tr><th>Url:</th><td><input type="text" name="url" value="http://" /></td></tr>
|
||||
<tr><th>Url:</th><td><input type="url" name="url" value="http://" /></td></tr>
|
||||
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
|
||||
|
||||
You may be thinking, why not just pass a dictionary of the initial values as
|
||||
|
@ -150,7 +150,7 @@ and the HTML output will include any validation errors::
|
|||
>>> f = CommentForm(default_data, auto_id=False)
|
||||
>>> print(f)
|
||||
<tr><th>Name:</th><td><input type="text" name="name" value="Your name" /></td></tr>
|
||||
<tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="text" name="url" value="http://" /></td></tr>
|
||||
<tr><th>Url:</th><td><ul class="errorlist"><li>Enter a valid URL.</li></ul><input type="url" name="url" value="http://" /></td></tr>
|
||||
<tr><th>Comment:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="comment" /></td></tr>
|
||||
|
||||
This is why ``initial`` values are only displayed for unbound forms. For bound
|
||||
|
@ -805,7 +805,7 @@ For each field, we describe the default widget used if you don't specify
|
|||
|
||||
.. class:: URLField(**kwargs)
|
||||
|
||||
* Default widget: :class:`TextInput`
|
||||
* Default widget: :class:`URLInput`
|
||||
* Empty value: ``''`` (an empty string)
|
||||
* Normalizes to: A Unicode object.
|
||||
* Validates that the given value is a valid URL.
|
||||
|
|
|
@ -139,7 +139,7 @@ provided for each widget will be rendered exactly the same::
|
|||
>>> f = CommentForm(auto_id=False)
|
||||
>>> f.as_table()
|
||||
<tr><th>Name:</th><td><input type="text" name="name" /></td></tr>
|
||||
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
|
||||
<tr><th>Url:</th><td><input type="url" name="url"/></td></tr>
|
||||
<tr><th>Comment:</th><td><input type="text" name="comment" /></td></tr>
|
||||
|
||||
On a real Web page, you probably don't want every widget to look the same. You
|
||||
|
@ -160,7 +160,7 @@ Django will then include the extra attributes in the rendered output:
|
|||
>>> f = CommentForm(auto_id=False)
|
||||
>>> f.as_table()
|
||||
<tr><th>Name:</th><td><input type="text" name="name" class="special"/></td></tr>
|
||||
<tr><th>Url:</th><td><input type="text" name="url"/></td></tr>
|
||||
<tr><th>Url:</th><td><input type="url" name="url"/></td></tr>
|
||||
<tr><th>Comment:</th><td><input type="text" name="comment" size="40"/></td></tr>
|
||||
|
||||
.. _styling-widget-classes:
|
||||
|
@ -403,6 +403,15 @@ These widgets make use of the HTML elements ``input`` and ``textarea``.
|
|||
|
||||
Text input: ``<input type="email" ...>``
|
||||
|
||||
``URLInput``
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. class:: URLInput
|
||||
|
||||
.. versionadded:: 1.6
|
||||
|
||||
Text input: ``<input type="url" ...>``
|
||||
|
||||
``PasswordInput``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -31,8 +31,9 @@ Minor features
|
|||
* Added :meth:`~django.db.models.query.QuerySet.earliest` for symmetry with
|
||||
:meth:`~django.db.models.query.QuerySet.latest`.
|
||||
|
||||
* The default widgets for :class:`~django.forms.EmailField` use
|
||||
the new type attribute available in HTML5 (type='email').
|
||||
* The default widgets for :class:`~django.forms.EmailField` and
|
||||
:class:`~django.forms.URLField` use the new type attributes available in
|
||||
HTML5 (type='email', type='url').
|
||||
|
||||
Backwards incompatible changes in 1.6
|
||||
=====================================
|
||||
|
@ -44,7 +45,7 @@ Backwards incompatible changes in 1.6
|
|||
|
||||
* If your CSS/Javascript code used to access HTML input widgets by type, you
|
||||
should review it as ``type='text'`` widgets might be now output as
|
||||
``type='email'`` depending on their corresponding field type.
|
||||
``type='email'`` or ``type='url'`` depending on their corresponding field type.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
|
|
@ -639,6 +639,7 @@ class FieldsTests(SimpleTestCase):
|
|||
|
||||
def test_urlfield_1(self):
|
||||
f = URLField()
|
||||
self.assertWidgetRendersTo(f, '<input type="url" name="f" id="id_f" />')
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, '')
|
||||
self.assertRaisesMessage(ValidationError, "'This field is required.'", f.clean, None)
|
||||
self.assertEqual('http://localhost/', f.clean('http://localhost'))
|
||||
|
@ -690,6 +691,7 @@ class FieldsTests(SimpleTestCase):
|
|||
|
||||
def test_urlfield_5(self):
|
||||
f = URLField(min_length=15, max_length=20)
|
||||
self.assertWidgetRendersTo(f, '<input id="id_f" type="url" name="f" maxlength="20" />')
|
||||
self.assertRaisesMessage(ValidationError, "'Ensure this value has at least 15 characters (it has 13).'", f.clean, 'http://f.com')
|
||||
self.assertEqual('http://example.com/', f.clean('http://example.com'))
|
||||
self.assertRaisesMessage(ValidationError, "'Ensure this value has at most 20 characters (it has 38).'", f.clean, 'http://abcdefghijklmnopqrstuvwxyz.com')
|
||||
|
|
|
@ -102,22 +102,22 @@ class GenericAdminViewTest(TestCase):
|
|||
# Works with no queryset
|
||||
formset = EpisodeMediaFormSet(instance=e)
|
||||
self.assertEqual(len(formset.forms), 5)
|
||||
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)
|
||||
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)
|
||||
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>')
|
||||
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)
|
||||
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)
|
||||
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>')
|
||||
|
||||
# A queryset can be used to alter display ordering
|
||||
formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.order_by('url'))
|
||||
self.assertEqual(len(formset.forms), 5)
|
||||
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)
|
||||
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)
|
||||
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>')
|
||||
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)
|
||||
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)
|
||||
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>')
|
||||
|
||||
# Works with a queryset that omits items
|
||||
formset = EpisodeMediaFormSet(instance=e, queryset=Media.objects.filter(url__endswith=".png"))
|
||||
self.assertEqual(len(formset.forms), 4)
|
||||
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)
|
||||
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>')
|
||||
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)
|
||||
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>')
|
||||
|
||||
def testGenericInlineFormsetFactory(self):
|
||||
# Regression test for #10522.
|
||||
|
|
Loading…
Reference in New Issue