summaryrefslogtreecommitdiff
path: root/django/newforms/forms.py
diff options
context:
space:
mode:
authorJacob Kaplan-Moss <jacob@jacobian.org>2008-07-19 01:22:26 +0000
committerJacob Kaplan-Moss <jacob@jacobian.org>2008-07-19 01:22:26 +0000
commit46786b4193e04d398532bbfc3dcf63c03c1793cb (patch)
tree8dfb9330ca0e377d89c29e3f67076231bbbbbc05 /django/newforms/forms.py
parent39af2738fd64ba7f4c4af0783590e2b2b7b88460 (diff)
Fixed #7741: django.newforms is now django.forms. This is obviously a backwards-incompatible change. There's a warning upon import of django.newforms itself, but deeper imports will raise errors.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7971 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/newforms/forms.py')
-rw-r--r--django/newforms/forms.py396
1 files changed, 0 insertions, 396 deletions
diff --git a/django/newforms/forms.py b/django/newforms/forms.py
deleted file mode 100644
index 753ee254bc..0000000000
--- a/django/newforms/forms.py
+++ /dev/null
@@ -1,396 +0,0 @@
-"""
-Form classes
-"""
-
-from copy import deepcopy
-
-from django.utils.datastructures import SortedDict
-from django.utils.html import escape
-from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode
-from django.utils.safestring import mark_safe
-
-from fields import Field, FileField
-from widgets import Media, media_property, TextInput, Textarea
-from util import flatatt, ErrorDict, ErrorList, ValidationError
-
-__all__ = ('BaseForm', 'Form')
-
-NON_FIELD_ERRORS = '__all__'
-
-def pretty_name(name):
- "Converts 'first_name' to 'First name'"
- name = name[0].upper() + name[1:]
- return name.replace('_', ' ')
-
-def get_declared_fields(bases, attrs, with_base_fields=True):
- """
- Create a list of form field instances from the passed in 'attrs', plus any
- similar fields on the base classes (in 'bases'). This is used by both the
- Form and ModelForm metclasses.
-
- If 'with_base_fields' is True, all fields from the bases are used.
- Otherwise, only fields in the 'declared_fields' attribute on the bases are
- used. The distinction is useful in ModelForm subclassing.
- Also integrates any additional media definitions
- """
- fields = [(field_name, attrs.pop(field_name)) for field_name, obj in attrs.items() if isinstance(obj, Field)]
- fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
-
- # If this class is subclassing another Form, add that Form's fields.
- # Note that we loop over the bases in *reverse*. This is necessary in
- # order to preserve the correct order of fields.
- if with_base_fields:
- for base in bases[::-1]:
- if hasattr(base, 'base_fields'):
- fields = base.base_fields.items() + fields
- else:
- for base in bases[::-1]:
- if hasattr(base, 'declared_fields'):
- fields = base.declared_fields.items() + fields
-
- return SortedDict(fields)
-
-class DeclarativeFieldsMetaclass(type):
- """
- Metaclass that converts Field attributes to a dictionary called
- 'base_fields', taking into account parent class 'base_fields' as well.
- """
- def __new__(cls, name, bases, attrs):
- attrs['base_fields'] = get_declared_fields(bases, attrs)
- new_class = super(DeclarativeFieldsMetaclass,
- cls).__new__(cls, name, bases, attrs)
- if 'media' not in attrs:
- new_class.media = media_property(new_class)
- return new_class
-
-class BaseForm(StrAndUnicode):
- # This is the main implementation of all the Form logic. Note that this
- # class is different than Form. See the comments by the Form class for more
- # information. Any improvements to the form API should be made to *this*
- # class, not to the Form class.
- def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
- initial=None, error_class=ErrorList, label_suffix=':',
- empty_permitted=False):
- self.is_bound = data is not None or files is not None
- self.data = data or {}
- self.files = files or {}
- self.auto_id = auto_id
- self.prefix = prefix
- self.initial = initial or {}
- self.error_class = error_class
- self.label_suffix = label_suffix
- self.empty_permitted = empty_permitted
- self._errors = None # Stores the errors after clean() has been called.
- self._changed_data = None
-
- # The base_fields class attribute is the *class-wide* definition of
- # fields. Because a particular *instance* of the class might want to
- # alter self.fields, we create self.fields here by copying base_fields.
- # Instances should always modify self.fields; they should not modify
- # self.base_fields.
- self.fields = deepcopy(self.base_fields)
-
- def __unicode__(self):
- return self.as_table()
-
- def __iter__(self):
- for name, field in self.fields.items():
- yield BoundField(self, field, name)
-
- def __getitem__(self, name):
- "Returns a BoundField with the given name."
- try:
- field = self.fields[name]
- except KeyError:
- raise KeyError('Key %r not found in Form' % name)
- return BoundField(self, field, name)
-
- def _get_errors(self):
- "Returns an ErrorDict for the data provided for the form"
- if self._errors is None:
- self.full_clean()
- return self._errors
- errors = property(_get_errors)
-
- def is_valid(self):
- """
- Returns True if the form has no errors. Otherwise, False. If errors are
- being ignored, returns False.
- """
- return self.is_bound and not bool(self.errors)
-
- def add_prefix(self, field_name):
- """
- Returns the field name with a prefix appended, if this Form has a
- prefix set.
-
- Subclasses may wish to override.
- """
- return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name
-
- def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row):
- "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
- top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
- output, hidden_fields = [], []
- for name, field in self.fields.items():
- bf = BoundField(self, field, name)
- bf_errors = self.error_class([escape(error) for error in bf.errors]) # Escape and cache in local variable.
- if bf.is_hidden:
- if bf_errors:
- top_errors.extend([u'(Hidden field %s) %s' % (name, force_unicode(e)) for e in bf_errors])
- hidden_fields.append(unicode(bf))
- else:
- if errors_on_separate_row and bf_errors:
- output.append(error_row % force_unicode(bf_errors))
- if bf.label:
- label = escape(force_unicode(bf.label))
- # Only add the suffix if the label does not end in
- # punctuation.
- if self.label_suffix:
- if label[-1] not in ':?.!':
- label += self.label_suffix
- label = bf.label_tag(label) or ''
- else:
- label = ''
- if field.help_text:
- help_text = help_text_html % force_unicode(field.help_text)
- else:
- help_text = u''
- output.append(normal_row % {'errors': force_unicode(bf_errors), 'label': force_unicode(label), 'field': unicode(bf), 'help_text': help_text})
- if top_errors:
- output.insert(0, error_row % force_unicode(top_errors))
- if hidden_fields: # Insert any hidden fields in the last row.
- str_hidden = u''.join(hidden_fields)
- if output:
- last_row = output[-1]
- # Chop off the trailing row_ender (e.g. '</td></tr>') and
- # insert the hidden fields.
- output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
- else:
- # If there aren't any rows in the output, just append the
- # hidden fields.
- output.append(str_hidden)
- return mark_safe(u'\n'.join(output))
-
- def as_table(self):
- "Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
- return self._html_output(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'<br />%s', False)
-
- def as_ul(self):
- "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
- return self._html_output(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False)
-
- def as_p(self):
- "Returns this form rendered as HTML <p>s."
- return self._html_output(u'<p>%(label)s %(field)s%(help_text)s</p>', u'%s', '</p>', u' %s', True)
-
- 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, self.error_class())
-
- def full_clean(self):
- """
- Cleans all of self.data and populates self._errors and
- self.cleaned_data.
- """
- self._errors = ErrorDict()
- if not self.is_bound: # Stop further processing.
- return
- self.cleaned_data = {}
- # If the form is permitted to be empty, and none of the form data has
- # changed from the initial data, short circuit any validation.
- if self.empty_permitted and not self.has_changed():
- return
- for name, field in self.fields.items():
- # value_from_datadict() gets the data from the data dictionaries.
- # 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, self.files, self.add_prefix(name))
- try:
- if isinstance(field, FileField):
- initial = self.initial.get(name, field.initial)
- value = field.clean(value, initial)
- else:
- value = field.clean(value)
- self.cleaned_data[name] = value
- if hasattr(self, 'clean_%s' % name):
- value = getattr(self, 'clean_%s' % name)()
- self.cleaned_data[name] = value
- except ValidationError, e:
- self._errors[name] = e.messages
- if name in self.cleaned_data:
- del self.cleaned_data[name]
- try:
- self.cleaned_data = self.clean()
- except ValidationError, e:
- self._errors[NON_FIELD_ERRORS] = e.messages
- if self._errors:
- delattr(self, 'cleaned_data')
-
- def clean(self):
- """
- Hook for doing any extra form-wide cleaning after Field.clean() been
- 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.cleaned_data
-
- def has_changed(self):
- """
- Returns True if data differs from initial.
- """
- return bool(self.changed_data)
-
- def _get_changed_data(self):
- if self._changed_data is None:
- self._changed_data = []
- # XXX: For now we're asking the individual widgets whether or not the
- # data has changed. It would probably be more efficient to hash the
- # initial data, store it in a hidden field, and compare a hash of the
- # submitted data, but we'd need a way to easily get the string value
- # for a given field. Right now, that logic is embedded in the render
- # method of each widget.
- for name, field in self.fields.items():
- prefixed_name = self.add_prefix(name)
- data_value = field.widget.value_from_datadict(self.data, self.files, prefixed_name)
- initial_value = self.initial.get(name, field.initial)
- if field.widget._has_changed(initial_value, data_value):
- self._changed_data.append(name)
- return self._changed_data
- changed_data = property(_get_changed_data)
-
- def _get_media(self):
- """
- Provide a description of all media required to render the widgets on this form
- """
- media = Media()
- for field in self.fields.values():
- media = media + field.widget.media
- return media
- media = property(_get_media)
-
- def is_multipart(self):
- """
- Returns True if the form needs to be multipart-encrypted, i.e. it has
- FileInput. Otherwise, False.
- """
- for field in self.fields.values():
- if field.widget.needs_multipart_form:
- return True
- return False
-
-class Form(BaseForm):
- "A collection of Fields, plus their associated data."
- # This is a separate class from BaseForm in order to abstract the way
- # self.fields is specified. This class (Form) is the one that does the
- # fancy metaclass stuff purely for the semantic sugar -- it allows one
- # to define a form using declarative syntax.
- # BaseForm itself has no way of designating self.fields.
- __metaclass__ = DeclarativeFieldsMetaclass
-
-class BoundField(StrAndUnicode):
- "A Field plus data"
- def __init__(self, form, field, name):
- self.form = form
- self.field = field
- self.name = name
- self.html_name = form.add_prefix(name)
- if self.field.label is None:
- self.label = pretty_name(name)
- else:
- self.label = self.field.label
- self.help_text = field.help_text or ''
-
- def __unicode__(self):
- """Renders this field as an HTML widget."""
- return self.as_widget()
-
- def _errors(self):
- """
- Returns an ErrorList for this field. Returns an empty ErrorList
- if there are none.
- """
- return self.form.errors.get(self.name, self.form.error_class())
- errors = property(_errors)
-
- def as_widget(self, widget=None, attrs=None):
- """
- Renders the field by rendering the passed widget, adding any HTML
- attributes passed as attrs. If no widget is specified, then the
- field's default widget will be used.
- """
- if not widget:
- widget = self.field.widget
- attrs = attrs or {}
- auto_id = self.auto_id
- if auto_id and 'id' not in attrs and 'id' not in widget.attrs:
- attrs['id'] = auto_id
- if not self.form.is_bound:
- data = self.form.initial.get(self.name, self.field.initial)
- if callable(data):
- data = data()
- else:
- data = self.data
- return widget.render(self.html_name, data, attrs=attrs)
-
- def as_text(self, attrs=None):
- """
- Returns a string of HTML for representing this as an <input type="text">.
- """
- return self.as_widget(TextInput(), attrs)
-
- def as_textarea(self, attrs=None):
- "Returns a string of HTML for representing this as a <textarea>."
- return self.as_widget(Textarea(), attrs)
-
- def as_hidden(self, attrs=None):
- """
- Returns a string of HTML for representing this as an <input type="hidden">.
- """
- return self.as_widget(self.field.hidden_widget(), attrs)
-
- def _data(self):
- """
- Returns the data for this BoundField, or None if it wasn't given.
- """
- return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name)
- data = property(_data)
-
- 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_:
- attrs = attrs and flatatt(attrs) or ''
- contents = '<label for="%s"%s>%s</label>' % (widget.id_for_label(id_), attrs, contents)
- return mark_safe(contents)
-
- def _is_hidden(self):
- "Returns True if this BoundField's widget is hidden."
- return self.field.widget.is_hidden
- is_hidden = property(_is_hidden)
-
- def _auto_id(self):
- """
- Calculates and returns the ID attribute for this BoundField, if the
- associated Form has specified auto_id. Returns an empty string otherwise.
- """
- auto_id = self.form.auto_id
- if auto_id and '%s' in smart_unicode(auto_id):
- return smart_unicode(auto_id) % self.html_name
- elif auto_id:
- return self.html_name
- return ''
- auto_id = property(_auto_id)