1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 | from django.newforms.forms import BaseForm, BoundField, ErrorList
from django.utils.html import escape
def include_formfield_callback(*alloweds):
def newfunc(f, **kwargs):
return [None, f.formfield(**kwargs)][f.name in alloweds]
newfunc.alloweds = alloweds
return newfunc
def form_fieldsets(*fieldsets):
allowed_fields = []
for fieldset in fieldsets:
allowed_fields += fieldset[1]['fields']
# TODO: Study whether we need to add separate name for each type we produce dynamically
return {
'form': type("DynamicFieldsetForm", (FieldsetForm,), {"fieldsets":fieldsets}),
'formfield_callback' : include_formfield_callback(*allowed_fields) }
class FieldsetForm(BaseForm):
def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row, normal_fieldset, fieldset_nameholder):
top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
output = []
for fieldset in self.fieldsets:
fieldset_name = fieldset[0]
fieldset_content = fieldset[1]
fieldset_field_names = []
fieldset_classes = ""
normal_fieldset_rows = []
# TODO: Test hidden fields
hidden_fields = []
# TODO: Implement error check (fields supposed to be list, and classes supposed to be string)
if fieldset_content.has_key('fields'):
fieldset_field_names = fieldset_content['fields']
if fieldset_content.has_key('classes'):
fieldset_classes = fieldset_content['classes']
normal_fieldset_nameholder = ""
if fieldset_name:
normal_fieldset_nameholder = fieldset_nameholder % {'fieldset_name':fieldset_name}
# Contents of this for loop is almost identical with BaseForm loop (except that I use normal_fieldset_rows at the end)
for field_name in fieldset_field_names:
name = field_name
field = self.fields[field_name]
bf = BoundField(self, field, name)
bf_errors = ErrorList([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, e) for e in bf_errors])
hidden_fields.append(unicode(bf))
else:
if errors_on_separate_row and bf_errors:
output.append(error_row % bf_errors)
label = bf.label and bf.label_tag(escape(bf.label + ':')) or ''
if field.help_text:
help_text = help_text_html % field.help_text
else:
help_text = u''
normal_fieldset_rows.append(normal_row % {'errors': bf_errors, 'label': label, 'field': unicode(bf), 'help_text': help_text})
output.append(normal_fieldset % {
'fieldset_nameholder': normal_fieldset_nameholder,
'fieldset_rows' : "\n".join(normal_fieldset_rows),
'fieldset_hidden_fields': "\n".join(hidden_fields),
'fieldset_classes' : fieldset_classes})
if top_errors:
output.insert(0, error_row % top_errors)
return u'\n'.join(output)
def as_table(self):
"Returns this form rendered as HTML <table> -- including the <table></table>."
# TODO: Is class attribute allowed to be empty?
# TODO: Add ability to add extra attributes to table element and fieldset element
# TODO: Think about moving all this to templates (since it sounds more sane)
# It is not done that way yet because this is just first scetch (and BaseForm did this way)
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, u'<fieldset class="%(fieldset_classes)s">%(fieldset_nameholder)s<table class="form">%(fieldset_rows)s</table>%(fieldset_hidden_fields)s</fieldset>', u"<legend>%(fieldset_name)s</legend>")
# I'm too excited to define the following, so we shall just pass at this point:
def as_ul(self):
pass
'''
"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):
pass
'''
"Returns this form rendered as HTML <p>s."
return self._html_output(u'<p>%(label)s %(field)s%(help_text)s</p>', u'<p>%s</p>', '</p>', u' %s', True)
'''
|
Comments
To make this work with django 1.0 wrap line 74 with mark_safe: mark_safe(u'n'.join(output))
In addition it was not clear to me how to use it in my form, so here is an example:
class MyForm(FieldsetForm):
#
More changes in FieldsetForm to make it work
class FieldsetForm(BaseForm): metaclass = DeclarativeFieldsMetaclass
#