diff options
| -rw-r--r-- | django/newforms/fields.py | 56 | ||||
| -rw-r--r-- | django/newforms/forms.py | 9 | ||||
| -rw-r--r-- | django/newforms/util.py | 5 | ||||
| -rw-r--r-- | django/newforms/widgets.py | 6 | ||||
| -rw-r--r-- | docs/testing.txt | 2 | ||||
| -rw-r--r-- | docs/url_dispatch.txt | 2 | ||||
| -rw-r--r-- | tests/regressiontests/forms/tests.py | 9 |
7 files changed, 51 insertions, 38 deletions
diff --git a/django/newforms/fields.py b/django/newforms/fields.py index 308790b07a..2370d964a5 100644 --- a/django/newforms/fields.py +++ b/django/newforms/fields.py @@ -86,15 +86,13 @@ class Field(object): class CharField(Field): def __init__(self, max_length=None, min_length=None, required=True, widget=None, label=None, initial=None): self.max_length, self.min_length = max_length, min_length - Field.__init__(self, required, widget, label, initial) + super(CharField, self).__init__(required, widget, label, initial) def clean(self, value): "Validates max_length and min_length. Returns a Unicode object." - Field.clean(self, value) + super(CharField, self).clean(value) if value in EMPTY_VALUES: - value = u'' - if not self.required: - return value + return u'' value = smart_unicode(value) if self.max_length is not None and len(value) > self.max_length: raise ValidationError(gettext(u'Ensure this value has at most %d characters.') % self.max_length) @@ -109,7 +107,7 @@ class CharField(Field): class IntegerField(Field): def __init__(self, max_value=None, min_value=None, required=True, widget=None, label=None, initial=None): self.max_value, self.min_value = max_value, min_value - Field.__init__(self, required, widget, label, initial) + super(IntegerField, self).__init__(required, widget, label, initial) def clean(self, value): """ @@ -117,7 +115,7 @@ class IntegerField(Field): of int(). Returns None for empty values. """ super(IntegerField, self).clean(value) - if not self.required and value in EMPTY_VALUES: + if value in EMPTY_VALUES: return None try: value = int(value) @@ -139,7 +137,7 @@ DEFAULT_DATE_INPUT_FORMATS = ( class DateField(Field): def __init__(self, input_formats=None, required=True, widget=None, label=None, initial=None): - Field.__init__(self, required, widget, label, initial) + super(DateField, self).__init__(required, widget, label, initial) self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS def clean(self, value): @@ -147,7 +145,7 @@ class DateField(Field): Validates that the input can be converted to a date. Returns a Python datetime.date object. """ - Field.clean(self, value) + super(DateField, self).clean(value) if value in EMPTY_VALUES: return None if isinstance(value, datetime.datetime): @@ -168,7 +166,7 @@ DEFAULT_TIME_INPUT_FORMATS = ( class TimeField(Field): def __init__(self, input_formats=None, required=True, widget=None, label=None, initial=None): - Field.__init__(self, required, widget, label, initial) + super(TimeField, self).__init__(required, widget, label, initial) self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS def clean(self, value): @@ -176,7 +174,7 @@ class TimeField(Field): Validates that the input can be converted to a time. Returns a Python datetime.time object. """ - Field.clean(self, value) + super(TimeField, self).clean(value) if value in EMPTY_VALUES: return None if isinstance(value, datetime.time): @@ -202,7 +200,7 @@ DEFAULT_DATETIME_INPUT_FORMATS = ( class DateTimeField(Field): def __init__(self, input_formats=None, required=True, widget=None, label=None, initial=None): - Field.__init__(self, required, widget, label, initial) + super(DateTimeField, self).__init__(required, widget, label, initial) self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS def clean(self, value): @@ -210,7 +208,7 @@ class DateTimeField(Field): Validates that the input can be converted to a datetime. Returns a Python datetime.datetime object. """ - Field.clean(self, value) + super(DateTimeField, self).clean(value) if value in EMPTY_VALUES: return None if isinstance(value, datetime.datetime): @@ -232,7 +230,7 @@ class RegexField(Field): error_message is an optional error message to use, if 'Enter a valid value' is too generic for you. """ - Field.__init__(self, required, widget, label, initial) + super(RegexField, self).__init__(required, widget, label, initial) if isinstance(regex, basestring): regex = re.compile(regex) self.regex = regex @@ -244,10 +242,11 @@ class RegexField(Field): Validates that the input matches the regular expression. Returns a Unicode object. """ - Field.clean(self, value) - if value in EMPTY_VALUES: value = u'' + super(RegexField, self).clean(value) + if value in EMPTY_VALUES: + value = u'' value = smart_unicode(value) - if not self.required and value == u'': + if value == u'': return value if self.max_length is not None and len(value) > self.max_length: raise ValidationError(gettext(u'Ensure this value has at most %d characters.') % self.max_length) @@ -282,13 +281,13 @@ except ImportError: class URLField(RegexField): def __init__(self, max_length=None, min_length=None, required=True, verify_exists=False, widget=None, label=None, initial=None, validator_user_agent=URL_VALIDATOR_USER_AGENT): - RegexField.__init__(self, url_re, max_length, min_length, gettext(u'Enter a valid URL.'), required, widget, label, initial) + super(URLField, self).__init__(url_re, max_length, min_length, gettext(u'Enter a valid URL.'), required, widget, label, initial) self.verify_exists = verify_exists self.user_agent = validator_user_agent def clean(self, value): - value = RegexField.clean(self, value) - if not self.required and value == u'': + value = super(URLField, self).clean(value) + if value == u'': return value if self.verify_exists: import urllib2 @@ -314,24 +313,25 @@ class BooleanField(Field): def clean(self, value): "Returns a Python boolean object." - Field.clean(self, value) + super(BooleanField, self).clean(value) return bool(value) class ChoiceField(Field): def __init__(self, choices=(), required=True, widget=Select, label=None, initial=None): if isinstance(widget, type): widget = widget(choices=choices) - Field.__init__(self, required, widget, label, initial) + super(ChoiceField, self).__init__(required, widget, label, initial) self.choices = choices def clean(self, value): """ Validates that the input is in self.choices. """ - value = Field.clean(self, value) - if value in EMPTY_VALUES: value = u'' + value = super(ChoiceField, self).clean(value) + if value in EMPTY_VALUES: + value = u'' value = smart_unicode(value) - if not self.required and value == u'': + if value == u'': return value valid_values = set([str(k) for k, v in self.choices]) if value not in valid_values: @@ -342,7 +342,7 @@ class MultipleChoiceField(ChoiceField): hidden_widget = MultipleHiddenInput def __init__(self, choices=(), required=True, widget=SelectMultiple, label=None, initial=None): - ChoiceField.__init__(self, choices, required, widget, label, initial) + super(MultipleChoiceField, self).__init__(choices, required, widget, label, initial) def clean(self, value): """ @@ -367,7 +367,7 @@ class MultipleChoiceField(ChoiceField): class ComboField(Field): def __init__(self, fields=(), required=True, widget=None, label=None, initial=None): - Field.__init__(self, required, widget, label, initial) + super(ComboField, self).__init__(required, widget, label, initial) # Set 'required' to False on the individual fields, because the # required validation will be handled by ComboField, not by those # individual fields. @@ -380,7 +380,7 @@ class ComboField(Field): Validates the given value against all of self.fields, which is a list of Field instances. """ - Field.clean(self, value) + super(ComboField, self).clean(value) for field in self.fields: value = field.clean(value) return value diff --git a/django/newforms/forms.py b/django/newforms/forms.py index 0b4687bcf3..1724a5a69f 100644 --- a/django/newforms/forms.py +++ b/django/newforms/forms.py @@ -6,7 +6,7 @@ from django.utils.datastructures import SortedDict, MultiValueDict from django.utils.html import escape from fields import Field from widgets import TextInput, Textarea, HiddenInput, MultipleHiddenInput -from util import StrAndUnicode, ErrorDict, ErrorList, ValidationError +from util import flatatt, StrAndUnicode, ErrorDict, ErrorList, ValidationError __all__ = ('BaseForm', 'Form') @@ -247,17 +247,20 @@ class BoundField(StrAndUnicode): return self.field.widget.value_from_datadict(self.form.data, self.html_name) data = property(_data) - def label_tag(self, contents=None): + def label_tag(self, contents=None, attrs=None): """ Wraps the given contents in a <label>, if the field has an ID attribute. Does not HTML-escape the contents. If contents aren't given, uses the field's HTML-escaped label. + + If attrs are given, they're used as HTML attributes on the <label> tag. """ contents = contents or escape(self.label) widget = self.field.widget id_ = widget.attrs.get('id') or self.auto_id if id_: - contents = '<label for="%s">%s</label>' % (widget.id_for_label(id_), contents) + attrs = attrs and flatatt(attrs) or '' + contents = '<label for="%s"%s>%s</label>' % (widget.id_for_label(id_), attrs, contents) return contents def _is_hidden(self): diff --git a/django/newforms/util.py b/django/newforms/util.py index a78623a17b..2fec9e4e2e 100644 --- a/django/newforms/util.py +++ b/django/newforms/util.py @@ -1,4 +1,9 @@ from django.conf import settings +from django.utils.html import escape + +# Converts a dictionary to a single string with key="value", XML-style with +# a leading space. Assumes keys do not need to be XML-escaped. +flatatt = lambda attrs: u''.join([u' %s="%s"' % (k, escape(v)) for k, v in attrs.items()]) def smart_unicode(s): if not isinstance(s, basestring): diff --git a/django/newforms/widgets.py b/django/newforms/widgets.py index 4bbd02dc63..e18026485e 100644 --- a/django/newforms/widgets.py +++ b/django/newforms/widgets.py @@ -8,7 +8,7 @@ __all__ = ( 'Select', 'SelectMultiple', 'RadioSelect', 'CheckboxSelectMultiple', ) -from util import StrAndUnicode, smart_unicode +from util import flatatt, StrAndUnicode, smart_unicode from django.utils.datastructures import MultiValueDict from django.utils.html import escape from itertools import chain @@ -18,10 +18,6 @@ try: except NameError: from sets import Set as set # Python 2.3 fallback -# Converts a dictionary to a single string with key="value", XML-style with -# a leading space. Assumes keys do not need to be XML-escaped. -flatatt = lambda attrs: u''.join([u' %s="%s"' % (k, escape(v)) for k, v in attrs.items()]) - class Widget(object): is_hidden = False # Determines whether this corresponds to an <input type="hidden">. diff --git a/docs/testing.txt b/docs/testing.txt index 7618aaea66..e7c1a3b161 100644 --- a/docs/testing.txt +++ b/docs/testing.txt @@ -13,7 +13,7 @@ changed unexpectedly as a result of the refactor. Testing a web application is a complex task, as there are many components of a web application that must be validated and tested. To help you test your application, Django provides a test execution -framework, and range of utilities that can be used to stimulate and +framework, and range of utilities that can be used to simulate and inspect various facets of a web application. This testing framework is currently under development, and may change diff --git a/docs/url_dispatch.txt b/docs/url_dispatch.txt index 00a7af027a..4991557859 100644 --- a/docs/url_dispatch.txt +++ b/docs/url_dispatch.txt @@ -286,7 +286,7 @@ With this in mind, the above example can be written more concisely as:: Note that you don't put a trailing dot (``"."``) in the prefix. Django puts that in automatically. -.. _Django overview: http://www.djangoproject.com/documentation/overview/ +.. _Django overview: ../overview/ Multiple view prefixes ---------------------- diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py index 2ae10dc0d6..336edf6cb7 100644 --- a/tests/regressiontests/forms/tests.py +++ b/tests/regressiontests/forms/tests.py @@ -2593,6 +2593,15 @@ field an "id" attribute. <input type="submit" /> </form> +The label_tag() method takes an optional attrs argument: a dictionary of HTML +attributes to add to the <label> tag. +>>> f = UserRegistration(auto_id='id_%s') +>>> for bf in f: +... print bf.label_tag(attrs={'class': 'pretty'}) +<label for="id_username" class="pretty">Username</label> +<label for="id_password1" class="pretty">Password1</label> +<label for="id_password2" class="pretty">Password2</label> + To display the errors that aren't associated with a particular field -- e.g., the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the template. If used on its own, it is displayed as a <ul> (or an empty string, if |
