mirror of
				https://github.com/django/django.git
				synced 2025-10-30 19:47:35 +00:00 
			
		
		
		
	 d4a0b27838
			
		
	
	
		d4a0b27838
		
	
	
	
	
		
			
			* Renamed the __unicode__ methods * Applied the python_2_unicode_compatible decorator * Removed the StrAndUnicode mix-in that is superseded by python_2_unicode_compatible * Kept the __unicode__ methods in classes that specifically test it under Python 2
		
			
				
	
	
		
			556 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			556 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| Form classes
 | |
| """
 | |
| 
 | |
| from __future__ import absolute_import, unicode_literals
 | |
| 
 | |
| import copy
 | |
| 
 | |
| from django.core.exceptions import ValidationError
 | |
| from django.forms.fields import Field, FileField
 | |
| from django.forms.util import flatatt, ErrorDict, ErrorList
 | |
| from django.forms.widgets import Media, media_property, TextInput, Textarea
 | |
| from django.utils.datastructures import SortedDict
 | |
| from django.utils.html import conditional_escape, format_html
 | |
| from django.utils.encoding import smart_text, force_text, python_2_unicode_compatible
 | |
| from django.utils.safestring import mark_safe
 | |
| from django.utils import six
 | |
| 
 | |
| 
 | |
| __all__ = ('BaseForm', 'Form')
 | |
| 
 | |
| NON_FIELD_ERRORS = '__all__'
 | |
| 
 | |
| def pretty_name(name):
 | |
|     """Converts 'first_name' to 'First name'"""
 | |
|     if not name:
 | |
|         return ''
 | |
|     return name.replace('_', ' ').capitalize()
 | |
| 
 | |
| 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 list(six.iteritems(attrs)) if isinstance(obj, Field)]
 | |
|     fields.sort(key=lambda x: x[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 = list(six.iteritems(base.base_fields)) + fields
 | |
|     else:
 | |
|         for base in bases[::-1]:
 | |
|             if hasattr(base, 'declared_fields'):
 | |
|                 fields = list(six.iteritems(base.declared_fields)) + 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
 | |
| 
 | |
| @python_2_unicode_compatible
 | |
| class BaseForm(object):
 | |
|     # 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 = copy.deepcopy(self.base_fields)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.as_table()
 | |
| 
 | |
|     def __iter__(self):
 | |
|         for name in self.fields:
 | |
|             yield self[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 add_initial_prefix(self, field_name):
 | |
|         """
 | |
|         Add a 'initial' prefix for checking dynamic initial values
 | |
|         """
 | |
|         return 'initial-%s' % self.add_prefix(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():
 | |
|             html_class_attr = ''
 | |
|             bf = self[name]
 | |
|             bf_errors = self.error_class([conditional_escape(error) for error in bf.errors]) # Escape and cache in local variable.
 | |
|             if bf.is_hidden:
 | |
|                 if bf_errors:
 | |
|                     top_errors.extend(['(Hidden field %s) %s' % (name, force_text(e)) for e in bf_errors])
 | |
|                 hidden_fields.append(six.text_type(bf))
 | |
|             else:
 | |
|                 # Create a 'class="..."' atribute if the row should have any
 | |
|                 # CSS classes applied.
 | |
|                 css_classes = bf.css_classes()
 | |
|                 if css_classes:
 | |
|                     html_class_attr = ' class="%s"' % css_classes
 | |
| 
 | |
|                 if errors_on_separate_row and bf_errors:
 | |
|                     output.append(error_row % force_text(bf_errors))
 | |
| 
 | |
|                 if bf.label:
 | |
|                     label = conditional_escape(force_text(bf.label))
 | |
|                     # Only add the suffix if the label does not end in
 | |
|                     # punctuation.
 | |
|                     if self.label_suffix:
 | |
|                         if label[-1] not in ':?.!':
 | |
|                             label = format_html('{0}{1}', label, self.label_suffix)
 | |
|                     label = bf.label_tag(label) or ''
 | |
|                 else:
 | |
|                     label = ''
 | |
| 
 | |
|                 if field.help_text:
 | |
|                     help_text = help_text_html % force_text(field.help_text)
 | |
|                 else:
 | |
|                     help_text = ''
 | |
| 
 | |
|                 output.append(normal_row % {
 | |
|                     'errors': force_text(bf_errors),
 | |
|                     'label': force_text(label),
 | |
|                     'field': six.text_type(bf),
 | |
|                     'help_text': help_text,
 | |
|                     'html_class_attr': html_class_attr
 | |
|                 })
 | |
| 
 | |
|         if top_errors:
 | |
|             output.insert(0, error_row % force_text(top_errors))
 | |
| 
 | |
|         if hidden_fields: # Insert any hidden fields in the last row.
 | |
|             str_hidden = ''.join(hidden_fields)
 | |
|             if output:
 | |
|                 last_row = output[-1]
 | |
|                 # Chop off the trailing row_ender (e.g. '</td></tr>') and
 | |
|                 # insert the hidden fields.
 | |
|                 if not last_row.endswith(row_ender):
 | |
|                     # This can happen in the as_p() case (and possibly others
 | |
|                     # that users write): if there are only top errors, we may
 | |
|                     # not be able to conscript the last row for our purposes,
 | |
|                     # so insert a new, empty row.
 | |
|                     last_row = (normal_row % {'errors': '', 'label': '',
 | |
|                                               'field': '', 'help_text':'',
 | |
|                                               'html_class_attr': html_class_attr})
 | |
|                     output.append(last_row)
 | |
|                 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('\n'.join(output))
 | |
| 
 | |
|     def as_table(self):
 | |
|         "Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
 | |
|         return self._html_output(
 | |
|             normal_row = '<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>',
 | |
|             error_row = '<tr><td colspan="2">%s</td></tr>',
 | |
|             row_ender = '</td></tr>',
 | |
|             help_text_html = '<br /><span class="helptext">%s</span>',
 | |
|             errors_on_separate_row = False)
 | |
| 
 | |
|     def as_ul(self):
 | |
|         "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
 | |
|         return self._html_output(
 | |
|             normal_row = '<li%(html_class_attr)s>%(errors)s%(label)s %(field)s%(help_text)s</li>',
 | |
|             error_row = '<li>%s</li>',
 | |
|             row_ender = '</li>',
 | |
|             help_text_html = ' <span class="helptext">%s</span>',
 | |
|             errors_on_separate_row = False)
 | |
| 
 | |
|     def as_p(self):
 | |
|         "Returns this form rendered as HTML <p>s."
 | |
|         return self._html_output(
 | |
|             normal_row = '<p%(html_class_attr)s>%(label)s %(field)s%(help_text)s</p>',
 | |
|             error_row = '%s',
 | |
|             row_ender = '</p>',
 | |
|             help_text_html = ' <span class="helptext">%s</span>',
 | |
|             errors_on_separate_row = 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 _raw_value(self, fieldname):
 | |
|         """
 | |
|         Returns the raw_value for a particular field name. This is just a
 | |
|         convenient wrapper around widget.value_from_datadict.
 | |
|         """
 | |
|         field = self.fields[fieldname]
 | |
|         prefix = self.add_prefix(fieldname)
 | |
|         return field.widget.value_from_datadict(self.data, self.files, prefix)
 | |
| 
 | |
|     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
 | |
|         self._clean_fields()
 | |
|         self._clean_form()
 | |
|         self._post_clean()
 | |
| 
 | |
|     def _clean_fields(self):
 | |
|         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 as e:
 | |
|                 self._errors[name] = self.error_class(e.messages)
 | |
|                 if name in self.cleaned_data:
 | |
|                     del self.cleaned_data[name]
 | |
| 
 | |
|     def _clean_form(self):
 | |
|         try:
 | |
|             self.cleaned_data = self.clean()
 | |
|         except ValidationError as e:
 | |
|             self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages)
 | |
| 
 | |
|     def _post_clean(self):
 | |
|         """
 | |
|         An internal hook for performing additional cleaning after form cleaning
 | |
|         is complete. Used for model validation in model forms.
 | |
|         """
 | |
|         pass
 | |
| 
 | |
|     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)
 | |
|                 if not field.show_hidden_initial:
 | |
|                     initial_value = self.initial.get(name, field.initial)
 | |
|                 else:
 | |
|                     initial_prefixed_name = self.add_initial_prefix(name)
 | |
|                     hidden_widget = field.hidden_widget()
 | |
|                     initial_value = hidden_widget.value_from_datadict(
 | |
|                         self.data, self.files, initial_prefixed_name)
 | |
|                 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-encoded, i.e. it has
 | |
|         FileInput. Otherwise, False.
 | |
|         """
 | |
|         for field in self.fields.values():
 | |
|             if field.widget.needs_multipart_form:
 | |
|                 return True
 | |
|         return False
 | |
| 
 | |
|     def hidden_fields(self):
 | |
|         """
 | |
|         Returns a list of all the BoundField objects that are hidden fields.
 | |
|         Useful for manual form layout in templates.
 | |
|         """
 | |
|         return [field for field in self if field.is_hidden]
 | |
| 
 | |
|     def visible_fields(self):
 | |
|         """
 | |
|         Returns a list of BoundField objects that aren't hidden fields.
 | |
|         The opposite of the hidden_fields() method.
 | |
|         """
 | |
|         return [field for field in self if not field.is_hidden]
 | |
| 
 | |
| class Form(six.with_metaclass(DeclarativeFieldsMetaclass, 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.
 | |
| 
 | |
| @python_2_unicode_compatible
 | |
| class BoundField(object):
 | |
|     "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)
 | |
|         self.html_initial_name = form.add_initial_prefix(name)
 | |
|         self.html_initial_id = form.add_initial_prefix(self.auto_id)
 | |
|         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 __str__(self):
 | |
|         """Renders this field as an HTML widget."""
 | |
|         if self.field.show_hidden_initial:
 | |
|             return self.as_widget() + self.as_hidden(only_initial=True)
 | |
|         return self.as_widget()
 | |
| 
 | |
|     def __iter__(self):
 | |
|         """
 | |
|         Yields rendered strings that comprise all widgets in this BoundField.
 | |
| 
 | |
|         This really is only useful for RadioSelect widgets, so that you can
 | |
|         iterate over individual radio buttons in a template.
 | |
|         """
 | |
|         for subwidget in self.field.widget.subwidgets(self.html_name, self.value()):
 | |
|             yield subwidget
 | |
| 
 | |
|     def __len__(self):
 | |
|         return len(list(self.__iter__()))
 | |
| 
 | |
|     def __getitem__(self, idx):
 | |
|         return list(self.__iter__())[idx]
 | |
| 
 | |
|     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, only_initial=False):
 | |
|         """
 | |
|         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:
 | |
|             if not only_initial:
 | |
|                 attrs['id'] = auto_id
 | |
|             else:
 | |
|                 attrs['id'] = self.html_initial_id
 | |
| 
 | |
|         if not only_initial:
 | |
|             name = self.html_name
 | |
|         else:
 | |
|             name = self.html_initial_name
 | |
|         return widget.render(name, self.value(), attrs=attrs)
 | |
| 
 | |
|     def as_text(self, attrs=None, **kwargs):
 | |
|         """
 | |
|         Returns a string of HTML for representing this as an <input type="text">.
 | |
|         """
 | |
|         return self.as_widget(TextInput(), attrs, **kwargs)
 | |
| 
 | |
|     def as_textarea(self, attrs=None, **kwargs):
 | |
|         "Returns a string of HTML for representing this as a <textarea>."
 | |
|         return self.as_widget(Textarea(), attrs, **kwargs)
 | |
| 
 | |
|     def as_hidden(self, attrs=None, **kwargs):
 | |
|         """
 | |
|         Returns a string of HTML for representing this as an <input type="hidden">.
 | |
|         """
 | |
|         return self.as_widget(self.field.hidden_widget(), attrs, **kwargs)
 | |
| 
 | |
|     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 value(self):
 | |
|         """
 | |
|         Returns the value for this BoundField, using the initial value if
 | |
|         the form is not bound or the data otherwise.
 | |
|         """
 | |
|         if not self.form.is_bound:
 | |
|             data = self.form.initial.get(self.name, self.field.initial)
 | |
|             if callable(data):
 | |
|                 data = data()
 | |
|         else:
 | |
|             data = self.field.bound_data(
 | |
|                 self.data, self.form.initial.get(self.name, self.field.initial)
 | |
|             )
 | |
|         return self.field.prepare_value(data)
 | |
| 
 | |
|     def label_tag(self, contents=None, attrs=None):
 | |
|         """
 | |
|         Wraps the given contents in a <label>, if the field has an ID attribute.
 | |
|         contents should be 'mark_safe'd to avoid HTML escaping. 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 conditional_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 = format_html('<label for="{0}"{1}>{2}</label>',
 | |
|                                    widget.id_for_label(id_), attrs, contents
 | |
|                                    )
 | |
|         return mark_safe(contents)
 | |
| 
 | |
|     def css_classes(self, extra_classes=None):
 | |
|         """
 | |
|         Returns a string of space-separated CSS classes for this field.
 | |
|         """
 | |
|         if hasattr(extra_classes, 'split'):
 | |
|             extra_classes = extra_classes.split()
 | |
|         extra_classes = set(extra_classes or [])
 | |
|         if self.errors and hasattr(self.form, 'error_css_class'):
 | |
|             extra_classes.add(self.form.error_css_class)
 | |
|         if self.field.required and hasattr(self.form, 'required_css_class'):
 | |
|             extra_classes.add(self.form.required_css_class)
 | |
|         return ' '.join(extra_classes)
 | |
| 
 | |
|     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_text(auto_id):
 | |
|             return smart_text(auto_id) % self.html_name
 | |
|         elif auto_id:
 | |
|             return self.html_name
 | |
|         return ''
 | |
|     auto_id = property(_auto_id)
 | |
| 
 | |
|     def _id_for_label(self):
 | |
|         """
 | |
|         Wrapper around the field widget's `id_for_label` method.
 | |
|         Useful, for example, for focusing on this field regardless of whether
 | |
|         it has a single widget or a MutiWidget.
 | |
|         """
 | |
|         widget = self.field.widget
 | |
|         id_ = widget.attrs.get('id') or self.auto_id
 | |
|         return widget.id_for_label(id_)
 | |
|     id_for_label = property(_id_for_label)
 |