from django import forms from django import forms from django.forms.util import ErrorDict, ErrorList from django.utils.encoding import force_unicode, smart_unicode from django.utils.safestring import mark_safe class Form(forms.Form): def add_error(self, field_name, message): if field_name is None: field_name = forms.NON_FIELD_ERRORS # self.errors is checked first because it triggers self.clean_all # but only if self._errors is None if self.errors is None: self._errors = ErrorDict() message = smart_unicode(message) messages = ErrorList([message]) if not self._errors.has_key(field_name): self._errors[field_name] = messages else: self._errors[field_name].extend(messages) def all_errors(self): if self.errors == {}: return None self.errors['%sALL' % forms.NON_FIELD_ERRORS] = ErrorList() for k in self.errors: self.errors['%sALL' % forms.NON_FIELD_ERRORS].extend(self.errors[k]) return self.errors.get('%sALL' % forms.NON_FIELD_ERRORS, self.error_class()) class XManagementForm(forms.formsets.ManagementForm): """ ``ManagementForm`` is used to keep track of how many form instances are displayed on the page. If adding new forms via javascript, you should increment the count field of this form as well. """ def __init__(self, data=None, extra_fields=None, *args, **kwargs): for f, tv in extra_fields.items(): self.base_fields[f] = tv[0](widget=forms.HiddenInput) if kwargs.has_key('initial'): kwargs['initial'][f] = tv[1] super(XManagementForm, self).__init__(data, *args, **kwargs) class BaseXFormSet(forms.formsets.BaseFormSet): def __init__(self, *args, **kwargs): self.added_forms = 0 super(BaseXFormSet, self).__init__(*args, **kwargs) def _management_form(self): """Returns the ManagementForm instance for this FormSet.""" if self.data or self.files: form = XManagementForm(self.data, auto_id=self.auto_id, prefix=self.prefix, extra_fields=self.extra_fields) #import pdb; pdb.set_trace() if not form.is_valid(): raise forms.ValidationError('ManagementForm data is missing or has been tampered with') else: form = XManagementForm(auto_id=self.auto_id, prefix=self.prefix, extra_fields=self.extra_fields, initial={ forms.formsets.TOTAL_FORM_COUNT: self.total_form_count(), forms.formsets.INITIAL_FORM_COUNT: self.initial_form_count() }) return form management_form = property(_management_form) def initial_form_count(self): """Returns the number of forms that are required/pre-populated in this FormSet.""" if not (self.data or self.files): initial_forms = self.initial and len(self.initial) or 0 initial_forms += self.added_forms if initial_forms > self.max_num > 0: initial_forms = self.max_num return initial_forms return super(BaseXFormSet, self).initial_form_count() def add_form(self, existing_form=None, **kwargs): self.added_forms = self.added_forms + 1 l_curIdx = len(self.forms) if existing_form: l_new_form = existing_form l_new_form.prefix = self.add_prefix(l_curIdx) else: l_new_form = self._construct_form(l_curIdx, **kwargs) l_new_form.form_index = l_curIdx self.forms.append(l_new_form) return l_new_form def formset_factory(form, formset=BaseXFormSet, extra=0, can_order=False, can_delete=False, max_num=0, extra_fields=None): """Return a FormSet for the given form class.""" attrs = {'form': form, 'extra': extra, 'can_order': can_order, 'can_delete': can_delete, 'max_num': max_num, 'extra_fields': extra_fields} return type(form.__name__ + 'FormSet', (formset,), attrs)