From 55d7f6519c8d13a685cff3f9873b5784fc511a87 Mon Sep 17 00:00:00 2001 From: Jason Pellerin Date: Mon, 4 Dec 2006 21:12:29 +0000 Subject: [multi-db] Merged trunk to [4158]. Some tests still failing. git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@4159 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/newforms/forms.py | 130 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 39 deletions(-) (limited to 'django/newforms/forms.py') diff --git a/django/newforms/forms.py b/django/newforms/forms.py index b8264fb691..4bc6173249 100644 --- a/django/newforms/forms.py +++ b/django/newforms/forms.py @@ -3,8 +3,9 @@ Form classes """ from django.utils.datastructures import SortedDict +from django.utils.html import escape from fields import Field -from widgets import TextInput, Textarea +from widgets import TextInput, Textarea, HiddenInput from util import ErrorDict, ErrorList, ValidationError NON_FIELD_ERRORS = '__all__' @@ -36,6 +37,7 @@ class Form(object): __metaclass__ = DeclarativeFieldsMetaclass def __init__(self, data=None, auto_id=False): # TODO: prefix stuff + self.ignore_errors = data is None self.data = data or {} self.auto_id = auto_id self.clean_data = None # Stores the data after clean() has been called. @@ -56,69 +58,78 @@ class Form(object): raise KeyError('Key %r not found in Form' % name) return BoundField(self, field, name) - def clean(self): - if self.__errors is None: - self.full_clean() - return self.clean_data - - def errors(self): + def _errors(self): "Returns an ErrorDict for self.data" if self.__errors is None: self.full_clean() return self.__errors + errors = property(_errors) def is_valid(self): """ - Returns True if the form has no errors. Otherwise, False. This exists - solely for convenience, so client code can use positive logic rather - than confusing negative logic ("if not form.errors()"). + Returns True if the form has no errors. Otherwise, False. If errors are + being ignored, returns False. """ - return not bool(self.errors()) + return not self.ignore_errors and not bool(self.errors) def as_table(self): "Returns this form rendered as HTML s -- excluding the
." - return u'\n'.join(['%s:%s' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()]) - - def as_ul(self): - "Returns this form rendered as HTML
  • s -- excluding the ." - return u'\n'.join(['
  • %s: %s
  • ' % (pretty_name(name), BoundField(self, field, name)) for name, field in self.fields.items()]) - - def as_table_with_errors(self): - "Returns this form rendered as HTML s, with errors." output = [] - if self.errors().get(NON_FIELD_ERRORS): + if self.errors.get(NON_FIELD_ERRORS): # Errors not corresponding to a particular field are displayed at the top. - output.append('' % '\n'.join(['
  • %s
  • ' % e for e in self.errors()[NON_FIELD_ERRORS]])) + output.append(u'%s' % self.non_field_errors()) for name, field in self.fields.items(): bf = BoundField(self, field, name) - if bf.errors: - output.append('' % '\n'.join(['
  • %s
  • ' % e for e in bf.errors])) - output.append('%s:%s' % (pretty_name(name), bf)) + if bf.is_hidden: + if bf.errors: + new_errors = ErrorList(['(Hidden field %s) %s' % (name, e) for e in bf.errors]) + output.append(u'%s' % new_errors) + output.append(str(bf)) + else: + if bf.errors: + output.append(u'%s' % bf.errors) + output.append(u'%s%s' % (bf.label_tag(escape(bf.verbose_name+':')), bf)) return u'\n'.join(output) - def as_ul_with_errors(self): - "Returns this form rendered as HTML
  • s, with errors." + def as_ul(self): + "Returns this form rendered as HTML
  • s -- excluding the ." output = [] - if self.errors().get(NON_FIELD_ERRORS): + if self.errors.get(NON_FIELD_ERRORS): # Errors not corresponding to a particular field are displayed at the top. - output.append('
  • ' % '\n'.join(['
  • %s
  • ' % e for e in self.errors()[NON_FIELD_ERRORS]])) + output.append(u'
  • %s
  • ' % self.non_field_errors()) for name, field in self.fields.items(): bf = BoundField(self, field, name) - line = '
  • ' - if bf.errors: - line += '' % '\n'.join(['
  • %s
  • ' % e for e in bf.errors]) - line += '%s: %s' % (pretty_name(name), bf) - output.append(line) + if bf.is_hidden: + if bf.errors: + new_errors = ErrorList(['(Hidden field %s) %s' % (name, e) for e in bf.errors]) + output.append(u'
  • %s
  • ' % new_errors) + output.append(str(bf)) + else: + output.append(u'
  • %s%s %s
  • ' % (bf.errors, bf.label_tag(escape(bf.verbose_name+':')), bf)) return u'\n'.join(output) + def non_field_errors(self): + """ + Returns an ErrorList of errors that aren't associated with a particular + field -- i.e., from Form.clean(). Returns an empty ErrorList if there + are none. + """ + return self.errors.get(NON_FIELD_ERRORS, ErrorList()) + def full_clean(self): """ Cleans all of self.data and populates self.__errors and self.clean_data. """ self.clean_data = {} errors = ErrorDict() + if self.ignore_errors: # Stop further processing. + self.__errors = errors + return for name, field in self.fields.items(): - value = self.data.get(name, None) + # value_from_datadict() gets the data from the dictionary. + # Each widget type knows how to retrieve its own data, because some + # widgets split data over several HTML fields. + value = field.widget.value_from_datadict(self.data, name) try: value = field.clean(value) self.clean_data[name] = value @@ -138,7 +149,9 @@ class Form(object): def clean(self): """ Hook for doing any extra form-wide cleaning after Field.clean() been - called on every field. + called on every field. Any ValidationError raised by this method will + not be associated with a particular field; it will have a special-case + association with the field named '__all__'. """ return self.clean_data @@ -153,7 +166,13 @@ class BoundField(object): "Renders this field as an HTML widget." # Use the 'widget' attribute on the field to determine which type # of HTML widget to use. - return self.as_widget(self._field.widget) + value = self.as_widget(self._field.widget) + if not isinstance(value, basestring): + # Some Widget render() methods -- notably RadioSelect -- return a + # "special" object rather than a string. Call the __str__() on that + # object to get its rendered value. + value = value.__str__() + return value def _errors(self): """ @@ -161,7 +180,7 @@ class BoundField(object): if there are none. """ try: - return self._form.errors()[self._name] + return self._form.errors[self._name] except KeyError: return ErrorList() errors = property(_errors) @@ -169,9 +188,9 @@ class BoundField(object): def as_widget(self, widget, attrs=None): attrs = attrs or {} auto_id = self.auto_id - if not attrs.has_key('id') and not widget.attrs.has_key('id') and auto_id: + if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id'): attrs['id'] = auto_id - return widget.render(self._name, self._form.data.get(self._name, None), attrs=attrs) + return widget.render(self._name, self.data, attrs=attrs) def as_text(self, attrs=None): """ @@ -183,6 +202,39 @@ class BoundField(object): "Returns a string of HTML for representing this as a