from django.forms import BaseForm, Field, HiddenInput class AutoPrefixedForm(BaseForm): '''A Form type that handles prefixes transparently. If a (non empty) prefix is passed, forms of this class have a hidden field named ``self.PREFIX_FIELD_NAME`` (by default "``PREFIX``") and value the prefix. Additionally, bound forms probe the passed data for this hidden field and set the prefix to it if found (and no prefix was passed explicitly at initialization). ''' PREFIX_FIELD_NAME = 'PREFIX' def __init__(self, *args, **kwargs): super(AutoPrefixedForm, self).__init__(*args, **kwargs) if not self.prefix and self.data: self.prefix = self.data.get(self.PREFIX_FIELD_NAME) if self.prefix: self.fields[self.PREFIX_FIELD_NAME] = Field(widget=HiddenInput, initial=self.prefix) def add_prefix(self, field_name): if field_name == self.PREFIX_FIELD_NAME: return field_name return super(AutoPrefixedForm,self).add_prefix(field_name) def autoprefixed(field_name=AutoPrefixedForm.PREFIX_FIELD_NAME): '''Decorates a Form class so that it handles prefixes transparently, as if subclassing :class:`AutoPrefixedForm`. Usage:: @autoprefixed class MyForm(forms.Form): ... or @autoprefixed(field_name='__prefix__') class MyForm(forms.Form): ... ''' if isinstance(field_name, type): return autoprefixed()(field_name) def decorator(cls): if not issubclass(cls, AutoPrefixedForm): cls.__bases__ = (AutoPrefixedForm,) + cls.__bases__ cls.PREFIX_FIELD_NAME = field_name return cls return decorator #==== usage =================== @autoprefixed class ContactForm(forms.Form): subject = forms.CharField(max_length=100) message = forms.CharField() sender = forms.EmailField() cc_myself = forms.BooleanField(required=False) f = ContactForm(prefix='bugform') print f.fields.keys() # ['subject', 'message', 'sender', 'cc_myself', 'PREFIX'] post_data = { 'bugform-subject': 'hello', 'bugform-message': 'Hi there', 'bugform-sender': 'foo@example.com', 'bugform-cc_myself': True, 'PREFIX': 'bugform', } # don't need to pass 'prefix' f = ContactForm(post_data) print f.prefix # 'bugform' print f.is_valid() # True print f.cleaned_data # {'PREFIX': 'bugform', 'cc_myself': True, 'message': u'Hi there', # 'sender': u'foo@example.com', 'subject': u'hello'}