=== modified file 'django/newforms/forms.py'
|
|
|
|
| 8 | 8 | from django.utils.html import conditional_escape |
| 9 | 9 | from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode |
| 10 | 10 | from django.utils.safestring import mark_safe |
| | 11 | from django.utils.text import capfirst |
| 11 | 12 | |
| 12 | 13 | from fields import Field, FileField |
| 13 | 14 | from widgets import TextInput, Textarea |
| … |
… |
|
| 24 | 25 | |
| 25 | 26 | class FormOptions(InheritableOptions): |
| 26 | 27 | _default_options = { |
| | 28 | # main options |
| 27 | 29 | 'fieldsets': None, |
| 28 | 30 | 'fields': None, |
| 29 | 31 | '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, |
| 30 | 41 | } |
| 31 | 42 | |
| 32 | 43 | class FormMetaclass(type): |
| … |
… |
|
| 73 | 84 | names = [name for name in new_cls._base_fields_pool if name not in new_cls._meta.exclude] |
| 74 | 85 | else: |
| 75 | 86 | 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]) |
| 77 | 88 | create_base_fields_from_base_fields_pool = classmethod(create_base_fields_from_base_fields_pool) |
| 78 | 89 | |
| 79 | 90 | def __new__(cls, name, bases, attrs): |
| … |
… |
|
| 89 | 100 | # class is different than Form. See the comments by the Form class for more |
| 90 | 101 | # information. Any improvements to the form API should be made to *this* |
| 91 | 102 | # 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): |
| 94 | 104 | self.is_bound = data is not None or files is not None |
| 95 | 105 | self.data = data or {} |
| 96 | 106 | self.files = files or {} |
| 97 | 107 | self.auto_id = auto_id |
| 98 | 108 | self.prefix = prefix |
| 99 | 109 | self.initial = initial or {} |
| 100 | | self.error_class = error_class |
| 101 | | self.label_suffix = label_suffix |
| 102 | 110 | self._errors = None # Stores the errors after clean() has been called. |
| 103 | 111 | |
| 104 | 112 | # The base_fields class attribute is the *class-wide* definition of |
| … |
… |
|
| 186 | 194 | |
| 187 | 195 | def hidden_fields_html_output(self, hidden_fields, hidden_fields_row): |
| 188 | 196 | "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)) |
| 190 | 202 | |
| 191 | 203 | def _html_output(self, output_type, top_errors_row, fieldset_start, fieldset_end, hidden_fields_row): |
| 192 | 204 | "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()." |
| … |
… |
|
| 221 | 233 | |
| 222 | 234 | def as_table(self): |
| 223 | 235 | "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>') |
| 225 | 237 | |
| 226 | 238 | def as_ul(self): |
| 227 | 239 | "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>') |
| 229 | 241 | |
| 230 | 242 | def as_p(self): |
| 231 | 243 | "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>') |
| 233 | 245 | |
| 234 | 246 | def non_field_errors(self): |
| 235 | 247 | """ |
| … |
… |
|
| 237 | 249 | field -- i.e., from Form.clean(). Returns an empty ErrorList if there |
| 238 | 250 | are none. |
| 239 | 251 | """ |
| 240 | | return self.errors.get(NON_FIELD_ERRORS, self.error_class()) |
| | 252 | return self.errors.get(NON_FIELD_ERRORS, self._meta.error_class()) |
| 241 | 253 | |
| 242 | 254 | def full_clean(self): |
| 243 | 255 | """ |
| … |
… |
|
| 248 | 260 | if not self.is_bound: # Stop further processing. |
| 249 | 261 | return |
| 250 | 262 | 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: |
| 252 | 268 | # value_from_datadict() gets the data from the data dictionaries. |
| 253 | 269 | # Each widget type knows how to retrieve its own data, because some |
| 254 | 270 | # widgets split data over several HTML fields. |
| … |
… |
|
| 264 | 280 | value = getattr(self, 'clean_%s' % name)() |
| 265 | 281 | self.cleaned_data[name] = value |
| 266 | 282 | except ValidationError, e: |
| 267 | | self._errors[name] = self.error_class(e.messages) |
| | 283 | self._errors[name] = self._meta.error_class(e.messages) |
| 268 | 284 | if name in self.cleaned_data: |
| 269 | 285 | del self.cleaned_data[name] |
| 270 | 286 | try: |
| 271 | 287 | self.cleaned_data = self.clean() |
| 272 | 288 | 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) |
| 274 | 290 | if self._errors: |
| 275 | 291 | delattr(self, 'cleaned_data') |
| 276 | 292 | |
| … |
… |
|
| 321 | 337 | Returns an ErrorList for this field. Returns an empty ErrorList |
| 322 | 338 | if there are none. |
| 323 | 339 | """ |
| 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()) |
| 325 | 341 | errors = property(_errors) |
| 326 | 342 | |
| 327 | 343 | def as_widget(self, widget=None, attrs=None): |
| … |
… |
|
| 372 | 388 | if self.field.label is None: |
| 373 | 389 | return pretty_name(self.name) |
| 374 | 390 | 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 |
| 376 | 395 | label = property(_label) |
| 377 | 396 | |
| 378 | 397 | def _label_tag(self): |
| 379 | 398 | "Returns label tag for this field as safe HTML code." |
| 380 | 399 | label = self.label |
| 381 | | if self.form.label_suffix: |
| | 400 | if self.form._meta.label_suffix: |
| 382 | 401 | # Only add the suffix if the label does not end in punctuation. |
| 383 | 402 | if label and label[-1] not in ':?.!': |
| 384 | | label += self.form.label_suffix |
| | 403 | label += self.form._meta.label_suffix |
| 385 | 404 | id_ = self.widget.attrs.get('id') or self.auto_id |
| 386 | 405 | if label and id_: |
| 387 | 406 | id_ = self.widget.id_for_label(id_) |
| … |
… |
|
| 400 | 419 | |
| 401 | 420 | def _row_attrs(self): |
| 402 | 421 | "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) |
| 404 | 431 | row_attrs = property(_row_attrs) |
| 405 | 432 | |
| 406 | 433 | def _is_hidden(self): |
=== modified file 'django/newforms/models.py'
|
|
|
|
| 9 | 9 | from django.utils.encoding import smart_unicode |
| 10 | 10 | from django.utils.datastructures import SortedDict, InheritableOptions |
| 11 | 11 | |
| 12 | | from util import ValidationError, ErrorList |
| | 12 | from util import ValidationError |
| 13 | 13 | from forms import FormOptions, FormMetaclass, BaseForm |
| 14 | 14 | from fields import Field, ChoiceField, EMPTY_VALUES |
| 15 | 15 | from widgets import Select, SelectMultiple, MultipleHiddenInput |
| … |
… |
|
| 252 | 252 | return new_cls |
| 253 | 253 | |
| 254 | 254 | class 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): |
| 258 | 256 | opts = self._meta |
| 259 | 257 | if instance is None: |
| 260 | 258 | # if we didn't get an instance, instantiate a new one |
| … |
… |
|
| 266 | 264 | # if initial was provided, it should override the values from instance |
| 267 | 265 | if initial is not None: |
| 268 | 266 | 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) |
| 270 | 268 | |
| 271 | 269 | def save(self, commit=True): |
| 272 | 270 | """ |