Ticket #6631: 01-newforms-options.diff

File 01-newforms-options.diff, 9.3 KB (added by Petr Marhoun <petr.marhoun@…>, 8 years ago)
  • django/newforms/forms.py

    === modified file 'django/newforms/forms.py'
     
    88from django.utils.html import conditional_escape
    99from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode
    1010from django.utils.safestring import mark_safe
     11from django.utils.text import capfirst
    1112
    1213from fields import Field, FileField
    1314from widgets import TextInput, Textarea
     
    2425
    2526class FormOptions(InheritableOptions):
    2627    _default_options = {
     28        # main options
    2729        'fieldsets': None,
    2830        'fields': None,
    2931        'exclude': None,
     32        # other options
     33        'error_class': ErrorList,
     34        'formfield_for_formfield': lambda self, formfield: formfield,
     35        'html_class_for_fields_with_errors': 'errors',
     36        'html_class_for_hidden_fields_row': 'hidden',
     37        'html_class_for_required_fields': 'required',
     38        'label_capitalization': True,
     39        'label_suffix': ':',
     40        'validation_order': None,
    3041    }
    3142
    3243class FormMetaclass(type):
     
    7384            names = [name for name in new_cls._base_fields_pool if name not in new_cls._meta.exclude]
    7485        else:
    7586            names = new_cls._base_fields_pool.keys()
    76         new_cls.base_fields = SortedDict([(name, new_cls._base_fields_pool[name]) for name in names])
     87        new_cls.base_fields = SortedDict([(name, new_cls._meta.formfield_for_formfield(new_cls._meta, new_cls._base_fields_pool[name])) for name in names])
    7788    create_base_fields_from_base_fields_pool = classmethod(create_base_fields_from_base_fields_pool)
    7889
    7990    def __new__(cls, name, bases, attrs):
     
    89100    # class is different than Form. See the comments by the Form class for more
    90101    # information. Any improvements to the form API should be made to *this*
    91102    # class, not to the Form class.
    92     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
    93                  initial=None, error_class=ErrorList, label_suffix=':'):
     103    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None):
    94104        self.is_bound = data is not None or files is not None
    95105        self.data = data or {}
    96106        self.files = files or {}
    97107        self.auto_id = auto_id
    98108        self.prefix = prefix
    99109        self.initial = initial or {}
    100         self.error_class = error_class
    101         self.label_suffix = label_suffix
    102110        self._errors = None # Stores the errors after clean() has been called.
    103111
    104112        # The base_fields class attribute is the *class-wide* definition of
     
    186194
    187195    def hidden_fields_html_output(self, hidden_fields, hidden_fields_row):
    188196        "Helper function for outputting HTML from a hidden fields row. Used by _html_output."
    189         return hidden_fields_row % u''.join(hidden_fields)
     197        if self._meta.html_class_for_hidden_fields_row:
     198            attrs = u' class="%s"' % self._meta.html_class_for_hidden_fields_row
     199        else:
     200            attrs = u''
     201        return hidden_fields_row % (attrs, u''.join(hidden_fields))
    190202
    191203    def _html_output(self, output_type, top_errors_row, fieldset_start, fieldset_end, hidden_fields_row):
    192204        "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
     
    221233
    222234    def as_table(self):
    223235        "Returns this form rendered as HTML <tr>s -- excluding the <table></table>."
    224         return self._html_output('table', u'<tr><td colspan="2">%s</td></tr>', u'%s\n<table>', u'</table>\n%s', u'<tr><td colspan="2">%s</td></tr>')
     236        return self._html_output('table', u'<tr><td colspan="2">%s</td></tr>', u'%s\n<table>', u'</table>\n%s', u'<tr%s><td colspan="2">%s</td></tr>')
    225237
    226238    def as_ul(self):
    227239        "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>."
    228         return self._html_output('ul', u'<li>%s</li>', u'%s\n<ul>', u'</ul>\n%s', u'<li>%s</li>')
     240        return self._html_output('ul', u'<li>%s</li>', u'%s\n<ul>', u'</ul>\n%s', u'<li%s>%s</li>')
    229241
    230242    def as_p(self):
    231243        "Returns this form rendered as HTML <p>s."
    232         return self._html_output('p', u'%s', u'%s', u'%s', u'<p>%s</p>')
     244        return self._html_output('p', u'%s', u'%s', u'%s', u'<p%s>%s</p>')
    233245
    234246    def non_field_errors(self):
    235247        """
     
    237249        field -- i.e., from Form.clean(). Returns an empty ErrorList if there
    238250        are none.
    239251        """
    240         return self.errors.get(NON_FIELD_ERRORS, self.error_class())
     252        return self.errors.get(NON_FIELD_ERRORS, self._meta.error_class())
    241253
    242254    def full_clean(self):
    243255        """
     
    248260        if not self.is_bound: # Stop further processing.
    249261            return
    250262        self.cleaned_data = {}
    251         for name, field in self.fields.items():
     263        if self._meta.validation_order:
     264            items = [(name, self.fields[name]) for name in self._meta.validation_order]
     265        else:
     266            items = self.fields.items()
     267        for name, field in items:
    252268            # value_from_datadict() gets the data from the data dictionaries.
    253269            # Each widget type knows how to retrieve its own data, because some
    254270            # widgets split data over several HTML fields.
     
    264280                    value = getattr(self, 'clean_%s' % name)()
    265281                    self.cleaned_data[name] = value
    266282            except ValidationError, e:
    267                 self._errors[name] = self.error_class(e.messages)
     283                self._errors[name] = self._meta.error_class(e.messages)
    268284                if name in self.cleaned_data:
    269285                    del self.cleaned_data[name]
    270286        try:
    271287            self.cleaned_data = self.clean()
    272288        except ValidationError, e:
    273             self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages)
     289            self._errors[NON_FIELD_ERRORS] = self._meta.error_class(e.messages)
    274290        if self._errors:
    275291            delattr(self, 'cleaned_data')
    276292
     
    321337        Returns an ErrorList for this field. Returns an empty ErrorList
    322338        if there are none.
    323339        """
    324         return self.form.errors.get(self.name, self.form.error_class())
     340        return self.form.errors.get(self.name, self.form._meta.error_class())
    325341    errors = property(_errors)
    326342
    327343    def as_widget(self, widget=None, attrs=None):
     
    372388        if self.field.label is None:
    373389            return pretty_name(self.name)
    374390        else:
    375             return conditional_escape(force_unicode(self.field.label))
     391            label = conditional_escape(force_unicode(self.field.label))
     392            if self.form._meta.label_capitalization:
     393                label = capfirst(label)
     394            return label
    376395    label = property(_label)
    377396
    378397    def _label_tag(self):
    379398        "Returns label tag for this field as safe HTML code."
    380399        label = self.label
    381         if self.form.label_suffix:
     400        if self.form._meta.label_suffix:
    382401            # Only add the suffix if the label does not end in punctuation.
    383402            if label and label[-1] not in ':?.!':
    384                 label += self.form.label_suffix
     403                label += self.form._meta.label_suffix
    385404        id_ = self.widget.attrs.get('id') or self.auto_id
    386405        if label and id_:
    387406            id_ = self.widget.id_for_label(id_)
     
    400419
    401420    def _row_attrs(self):
    402421        "Returns row attributes for this field as safe HTML code."
    403         return flatatt(self.widget.row_attrs)
     422        attrs = self.widget.row_attrs.copy()
     423        class_list = attrs.pop('class', '').split()
     424        if self.form._meta.html_class_for_fields_with_errors and self.errors:
     425            class_list.append(self.form._meta.html_class_for_fields_with_errors)
     426        if self.form._meta.html_class_for_required_fields and self.field.required:
     427            class_list.append(self.form._meta.html_class_for_required_fields)
     428        if class_list:
     429            attrs['class'] = u' '.join(class_list)
     430        return flatatt(attrs)
    404431    row_attrs = property(_row_attrs)
    405432
    406433    def _is_hidden(self):
  • django/newforms/models.py

    === modified file 'django/newforms/models.py'
     
    99from django.utils.encoding import smart_unicode
    1010from django.utils.datastructures import SortedDict, InheritableOptions
    1111
    12 from util import ValidationError, ErrorList
     12from util import ValidationError
    1313from forms import FormOptions, FormMetaclass, BaseForm
    1414from fields import Field, ChoiceField, EMPTY_VALUES
    1515from widgets import Select, SelectMultiple, MultipleHiddenInput
     
    252252        return new_cls
    253253
    254254class BaseModelForm(BaseForm):
    255     def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
    256                  initial=None, error_class=ErrorList, label_suffix=':',
    257                  instance=None):
     255    def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, instance=None):
    258256        opts = self._meta
    259257        if instance is None:
    260258            # if we didn't get an instance, instantiate a new one
     
    266264        # if initial was provided, it should override the values from instance
    267265        if initial is not None:
    268266            object_data.update(initial)
    269         BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix)
     267        BaseForm.__init__(self, data, files, auto_id, prefix, object_data)
    270268
    271269    def save(self, commit=True):
    272270        """
Back to Top