diff options
| author | Jacob Kaplan-Moss <jacob@jacobian.org> | 2008-07-19 01:22:26 +0000 |
|---|---|---|
| committer | Jacob Kaplan-Moss <jacob@jacobian.org> | 2008-07-19 01:22:26 +0000 |
| commit | 46786b4193e04d398532bbfc3dcf63c03c1793cb (patch) | |
| tree | 8dfb9330ca0e377d89c29e3f67076231bbbbbc05 /django/newforms/forms.py | |
| parent | 39af2738fd64ba7f4c4af0783590e2b2b7b88460 (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.py | 396 |
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) |
