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 -- including the
." # 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'%(label)s%(errors)s%(field)s%(help_text)s', u'%s', '', u'
%s', False, u'
%(fieldset_nameholder)s%(fieldset_rows)s
%(fieldset_hidden_fields)s
', u"%(fieldset_name)s") # 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
  • s -- excluding the ." return self._html_output(u'
  • %(errors)s%(label)s %(field)s%(help_text)s
  • ', u'
  • %s
  • ', '', u' %s', False) ''' def as_p(self): pass ''' "Returns this form rendered as HTML

    s." return self._html_output(u'

    %(label)s %(field)s%(help_text)s

    ', u'

    %s

    ', '

    ', u' %s', True) '''