from django import forms from django.template import loader, Context from django.core.context_processors import media as media_processor class StackedItem(object): """ An item inside a ``FieldStack`` Can be either an actual form field, or a group of fields """ def __init__(self, form, stackitem): self.form = form self.stackitem = stackitem def is_group(self): if isinstance(self.stackitem, tuple): return True return False def __iter__(self): if not self.is_group(): raise AttributeError('This stacked item is not a group and therefore not iterable') for stackitem in self.stackitem: yield StackedItem(self.form, stackitem) def __unicode__(self): """ Either render the html, or print some information about this group of fields """ if self.is_group(): return u'StackGroup %s' % self.stackitem tpl = self.form.get_field_template() context_dict = dict( form=self.form, field=self.form[self.stackitem], ) context_dict.update(media_processor(None)) return tpl.render( Context( context_dict ) ) return unicode(self.form[self.stackitem]) class FieldStack(object): """ A stack of fields yielded by ``StackedForm`` """ def __init__(self, form, stack): self.form = form self.stack = stack def __iter__(self): for stackitem in self.stack.get('fields', ()): yield StackedItem(self.form, stackitem) def __len__(self): # ... or the for templatetag throws an error return len(self.stack.get('fields', ())) def __getattr__(self, name): return self.stack.get(name, None) class StackedForm(object): """ Mixin to provide support for stacked forms with or without grouped fields. One particular example of such a form (without groups though) is the Basecamp signup page https://signup.37signals.com/basecamp/Plus/signup/new Example: # ---------------------------------------------------------- Django form from django import forms from toolbox.forms import StackedForm class MyForm(forms.Form, StackedForm): username = forms.CharField() pw1 = forms.CharField() pw2 = forms.CharField() email1 = forms.CharField() email2 = forms.CharField() first_name = forms.CharField() last_name = forms.CharField() website = forms.CharField() twitter = forms.CharField() facebook = forms.CharField() class Stack: stack = ( dict( label = 'User Information', fields = ('username',('first_name','last_name')) ), dict( label = 'Security Information', css_class = 'smaller-h1', fields = (('email1','email2'),('pw1','pw2')) ), dict( label = 'Elsewhere', fields = ('website','twitter','facebook') ) ) # ------------------------------------------------------------- Template
# ---------------------------------------------------- stacked_form.html{{ field }} {{ field.help_text }}
# --------------------------------------------------------------- Output