Skip to content

Instantly share code, notes, and snippets.

@imomaliev
Last active May 28, 2018 04:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save imomaliev/1889aac5b42ce33c5202dd328657a6eb to your computer and use it in GitHub Desktop.
Save imomaliev/1889aac5b42ce33c5202dd328657a6eb to your computer and use it in GitHub Desktop.
Django multiple forms CBV
# coding: utf-8
from __future__ import unicode_literals, absolute_import
from django.http.response import HttpResponseForbidden, HttpResponseRedirect
from django.views.generic.base import TemplateResponseMixin, ContextMixin
from django.views.generic.edit import ProcessFormView
class MultiFormMixin(ContextMixin):
form_classes = {}
prefixes = {}
success_urls = {}
grouped_forms = {}
initial = {}
prefix = None
success_url = None
def get_context_data(self, **kwargs):
forms = kwargs.pop('forms')
context_data = super(MultiFormMixin, self).get_context_data(**kwargs)
context_data.update({'%s_form' % key: value for key, value in forms.items()})
return context_data
def get_form_classes(self):
return self.form_classes
def get_forms(self, form_classes, form_names=None, bind_all=False):
return dict(
[(key, self._create_form(key, klass, (form_names and key in form_names) or bind_all)) for key, klass in form_classes.items()]
)
def get_form_kwargs(self, form_name, bind_form=False):
kwargs = {}
kwargs.update({'initial': self.get_initial(form_name)})
kwargs.update({'prefix': self.get_prefix(form_name)})
if bind_form:
kwargs.update(self._bind_form_data())
return kwargs
def forms_valid(self, forms, form_name):
form_valid_method = '%s_form_valid' % form_name
if hasattr(self, form_valid_method):
return getattr(self, form_valid_method)(forms[form_name])
else:
return self.redirect_to_success_url()
def redirect_to_success_url(self, form_name=None):
return HttpResponseRedirect(self.get_success_url(form_name))
def forms_invalid(self, forms):
return self.render_to_response(self.get_context_data(forms=forms))
def get_initial(self, form_name):
initial_method = 'get_%s_form_initial' % form_name
if hasattr(self, initial_method):
return getattr(self, initial_method)()
else:
return self.initial.copy()
def get_prefix(self, form_name):
return self.prefixes.get(form_name, self.prefix)
def get_success_url(self, form_name=None):
return self.success_urls.get(form_name, self.success_url)
def _create_form(self, form_name, klass, bind_form):
form_kwargs = self.get_form_kwargs(form_name, bind_form)
form_create_method = 'create_%s_form' % form_name
if hasattr(self, form_create_method):
form = getattr(self, form_create_method)(klass, **form_kwargs)
else:
form = klass(**form_kwargs)
return form
def _bind_form_data(self):
if self.request.method in ('POST', 'PUT'):
return{'data': self.request.POST,
'files': self.request.FILES,}
return {}
class ProcessMultipleFormsView(ProcessFormView):
def get(self, request, *args, **kwargs):
form_classes = self.get_form_classes()
forms = self.get_forms(form_classes)
return self.render_to_response(self.get_context_data(forms=forms))
def post(self, request, *args, **kwargs):
form_classes = self.get_form_classes()
form_name = request.POST.get('action')
if self._individual_exists(form_name):
return self._process_individual_form(form_name, form_classes)
elif self._group_exists(form_name):
return self._process_grouped_forms(form_name, form_classes)
else:
return self._process_all_forms(form_classes)
def _individual_exists(self, form_name):
return form_name in self.form_classes
def _group_exists(self, group_name):
return group_name in self.grouped_forms
def _process_individual_form(self, form_name, form_classes):
forms = self.get_forms(form_classes, (form_name,))
form = forms.get(form_name)
if not form:
return HttpResponseForbidden()
elif form.is_valid():
return self.forms_valid(forms, form_name)
else:
return self.forms_invalid(forms)
def _process_grouped_forms(self, group_name, form_classes):
form_names = self.grouped_forms[group_name]
forms = self.get_forms(form_classes, form_names)
if all([forms.get(form_name).is_valid() for form_name in form_names.values()]):
return self.forms_valid(forms)
else:
return self.forms_invalid(forms)
def _process_all_forms(self, form_classes):
forms = self.get_forms(form_classes, None, True)
if all([form.is_valid() for form in forms.values()]):
return self.forms_valid(forms)
else:
return self.forms_invalid(forms)
class BaseMultipleFormsView(MultiFormMixin, ProcessMultipleFormsView):
"""
A base view for displaying several forms.
"""
class MultiFormsView(TemplateResponseMixin, BaseMultipleFormsView):
"""
A view for displaying several forms, and rendering a template response.
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment