=== modified file 'django/newforms/forms.py'
|
|
|
7 | 7 | from django.utils.html import conditional_escape |
8 | 8 | from django.utils.encoding import StrAndUnicode, smart_unicode, force_unicode |
9 | 9 | from django.utils.safestring import mark_safe |
| 10 | from django.utils.text import capfirst |
10 | 11 | |
11 | 12 | from fields import FileField |
12 | 13 | from widgets import TextInput, Textarea |
… |
… |
|
24 | 25 | |
25 | 26 | class FormOptions(object): |
26 | 27 | def __init__(self, options=None): |
| 28 | # main options |
27 | 29 | self.fieldsets = getattr(options, 'fieldsets', None) |
28 | 30 | self.fields = getattr(options, 'fields', None) |
29 | 31 | self.exclude = getattr(options, 'exclude', None) |
| 32 | # other options |
| 33 | self.error_class = getattr(options, 'error_class', ErrorList) |
| 34 | self.error_row_class = getattr(options, 'error_row_class', 'error') |
| 35 | self.hidden_row_class = getattr(options, 'hidden_row_class', 'hidden') |
| 36 | self.label_capfirst = getattr(options, 'label_capfirst', True) |
| 37 | self.label_suffix = getattr(options, 'label_suffix', ':') |
| 38 | self.required_row_class = getattr(options, 'required_row_class', 'required') |
| 39 | self.validation_order = getattr(options, 'validation_order', None) |
30 | 40 | |
31 | 41 | class FormMetaclass(type): |
32 | 42 | def __new__(cls, name, bases, attrs): |
… |
… |
|
42 | 52 | # class is different than Form. See the comments by the Form class for more |
43 | 53 | # information. Any improvements to the form API should be made to *this* |
44 | 54 | # class, not to the Form class. |
45 | | def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, |
46 | | initial=None, error_class=ErrorList, label_suffix=':'): |
| 55 | def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None): |
47 | 56 | self.is_bound = data is not None or files is not None |
48 | 57 | self.data = data or {} |
49 | 58 | self.files = files or {} |
50 | 59 | self.auto_id = auto_id |
51 | 60 | self.prefix = prefix |
52 | 61 | self.initial = initial or {} |
53 | | self.error_class = error_class |
54 | | self.label_suffix = label_suffix |
55 | 62 | self._errors = None # Stores the errors after clean() has been called. |
56 | 63 | |
57 | 64 | # The base_fields class attribute is the *class-wide* definition of |
… |
… |
|
120 | 127 | def _label_tag_html_output(self, bf, label_tag_html): |
121 | 128 | "Helper function for outputting HTML from a label. Used by _widget_html_output." |
122 | 129 | label, label_id = bf.label, bf.label_id |
123 | | if self.label_suffix and label and label[-1] not in ':?.!': |
124 | | label += self.label_suffix |
| 130 | if self._meta.label_suffix and label and label[-1] not in ':?.!': |
| 131 | label += self._meta.label_suffix |
125 | 132 | if label and label_id: |
126 | 133 | return label_tag_html % { |
127 | 134 | 'label': label, |
… |
… |
|
178 | 185 | |
179 | 186 | def _hidden_fields_html_output(self, hidden_fields, hidden_fields_html): |
180 | 187 | "Helper function for outputting HTML from a hidden fields. Used by _html_output." |
| 188 | if self._meta.hidden_row_class: |
| 189 | attrs = u' class="%s"' % self._meta.hidden_row_class |
| 190 | else: |
| 191 | attrs = u'' |
181 | 192 | return hidden_fields_html % { |
| 193 | 'attrs': attrs, |
182 | 194 | 'hidden_fields': u''.join(hidden_fields), |
183 | 195 | } |
184 | 196 | |
… |
… |
|
222 | 234 | 'fieldset_start_html': u'<fieldset%(attrs)s>\n%(legend_tag)s<table>', |
223 | 235 | 'fieldset_end_html': u'</table>\n</fieldset>', |
224 | 236 | 'legend_tag_html': u'<legend>%(legend)s</legend>\n', |
225 | | 'hidden_fields_html': u'<tr><td colspan="2">%(hidden_fields)s</td></tr>', |
| 237 | 'hidden_fields_html': u'<tr%(attrs)s><td colspan="2">%(hidden_fields)s</td></tr>', |
226 | 238 | } |
227 | 239 | return self._html_output(**kwargs) |
228 | 240 | |
… |
… |
|
236 | 248 | 'fieldset_start_html': u'<fieldset%(attrs)s>\n%(legend_tag)s<ul>', |
237 | 249 | 'fieldset_end_html': u'</ul>\n</fieldset>', |
238 | 250 | 'legend_tag_html': u'<legend>%(legend)s</legend>\n', |
239 | | 'hidden_fields_html': u'<li>%(hidden_fields)s</li>', |
| 251 | 'hidden_fields_html': u'<li%(attrs)s>%(hidden_fields)s</li>', |
240 | 252 | } |
241 | 253 | return self._html_output(**kwargs) |
242 | 254 | |
… |
… |
|
250 | 262 | 'fieldset_start_html': u'<fieldset%(attrs)s>\n%(legend_tag)s', |
251 | 263 | 'fieldset_end_html': u'</fieldset>', |
252 | 264 | 'legend_tag_html': u'<legend>%(legend)s</legend>\n', |
253 | | 'hidden_fields_html': u'<p>%(hidden_fields)s</p>', |
| 265 | 'hidden_fields_html': u'<p%(attrs)>%(hidden_fields)s</p>', |
254 | 266 | } |
255 | 267 | return self._html_output(**kwargs) |
256 | 268 | |
… |
… |
|
260 | 272 | field -- i.e., from Form.clean(). Returns an empty ErrorList if there |
261 | 273 | are none. |
262 | 274 | """ |
263 | | return self.errors.get(NON_FIELD_ERRORS, self.error_class()) |
| 275 | return self.errors.get(NON_FIELD_ERRORS, self._meta.error_class()) |
264 | 276 | |
265 | 277 | def full_clean(self): |
266 | 278 | """ |
… |
… |
|
271 | 283 | if not self.is_bound: # Stop further processing. |
272 | 284 | return |
273 | 285 | self.cleaned_data = {} |
274 | | for name, field in self.fields.items(): |
| 286 | if self._meta.validation_order: |
| 287 | items = [(name, self.fields[name]) for name in self._meta.validation_order] |
| 288 | else: |
| 289 | items = self.fields.items() |
| 290 | for name, field in items: |
275 | 291 | # value_from_datadict() gets the data from the data dictionaries. |
276 | 292 | # Each widget type knows how to retrieve its own data, because some |
277 | 293 | # widgets split data over several HTML fields. |
… |
… |
|
287 | 303 | value = getattr(self, 'clean_%s' % name)() |
288 | 304 | self.cleaned_data[name] = value |
289 | 305 | except ValidationError, e: |
290 | | self._errors[name] = self.error_class(e.messages) |
| 306 | self._errors[name] = self._meta.error_class(e.messages) |
291 | 307 | if name in self.cleaned_data: |
292 | 308 | del self.cleaned_data[name] |
293 | 309 | try: |
294 | 310 | self.cleaned_data = self.clean() |
295 | 311 | except ValidationError, e: |
296 | | self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages) |
| 312 | self._errors[NON_FIELD_ERRORS] = self._meta.error_class(e.messages) |
297 | 313 | if self._errors: |
298 | 314 | delattr(self, 'cleaned_data') |
299 | 315 | |
… |
… |
|
344 | 360 | Returns an ErrorList for this field. Returns an empty ErrorList |
345 | 361 | if there are none. |
346 | 362 | """ |
347 | | return self.form.errors.get(self.name, self.form.error_class()) |
| 363 | return self.form.errors.get(self.name, self.form._meta.error_class()) |
348 | 364 | errors = property(_errors) |
349 | 365 | |
350 | 366 | def as_widget(self, widget=None, attrs=None): |
… |
… |
|
395 | 411 | if self.field.label is None: |
396 | 412 | return pretty_name(self.name) |
397 | 413 | else: |
398 | | return conditional_escape(force_unicode(self.field.label)) |
| 414 | label = conditional_escape(force_unicode(self.field.label)) |
| 415 | if self.form._meta.label_capfirst: |
| 416 | label = capfirst(label) |
| 417 | return label |
399 | 418 | label = property(_label) |
400 | 419 | |
401 | 420 | def _label_id(self): |
… |
… |
|
414 | 433 | help_text = property(_help_text) |
415 | 434 | |
416 | 435 | def _row_attrs(self): |
417 | | "Returns row attributes for this field as safe HTML." |
418 | | return flatatt(self.widget.row_attrs) |
| 436 | "Returns row attributes for this field as safe HTML code." |
| 437 | attrs = self.widget.row_attrs.copy() |
| 438 | class_list = attrs.pop('class', '').split() |
| 439 | if self.form._meta.error_row_class and self.errors: |
| 440 | class_list.append(self.form._meta.error_row_class) |
| 441 | if self.form._meta.required_row_class and self.field.required: |
| 442 | class_list.append(self.form._meta.required_row_class) |
| 443 | if class_list: |
| 444 | attrs['class'] = u' '.join(class_list) |
| 445 | return flatatt(attrs) |
419 | 446 | row_attrs = property(_row_attrs) |
420 | 447 | |
421 | 448 | def label_tag(self, contents=None, attrs=None): |
=== modified file 'django/newforms/models.py'
|
|
|
9 | 9 | from django.utils.encoding import smart_unicode |
10 | 10 | from django.utils.datastructures import SortedDict |
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 |
… |
… |
|
221 | 221 | return new_class |
222 | 222 | |
223 | 223 | class BaseModelForm(BaseForm): |
224 | | def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, |
225 | | initial=None, error_class=ErrorList, label_suffix=':', |
226 | | instance=None): |
| 224 | def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, instance=None): |
227 | 225 | opts = self._meta |
228 | 226 | if instance is None: |
229 | 227 | # if we didn't get an instance, instantiate a new one |
… |
… |
|
235 | 233 | # if initial was provided, it should override the values from instance |
236 | 234 | if initial is not None: |
237 | 235 | object_data.update(initial) |
238 | | BaseForm.__init__(self, data, files, auto_id, prefix, object_data, error_class, label_suffix) |
| 236 | BaseForm.__init__(self, data, files, auto_id, prefix, object_data) |
239 | 237 | |
240 | 238 | def save(self, commit=True): |
241 | 239 | """ |