mirror of
https://github.com/Hopiu/django-fobi.git
synced 2026-05-12 22:53:12 +00:00
221 lines
7.7 KiB
Python
221 lines
7.7 KiB
Python
from collections import OrderedDict
|
|
|
|
from django.forms.forms import BaseForm
|
|
from django.forms.widgets import media_property
|
|
from django.http import HttpResponseRedirect
|
|
from django.urls import reverse
|
|
|
|
from formtools.wizard.views import (
|
|
CookieWizardView,
|
|
SessionWizardView,
|
|
WizardView,
|
|
)
|
|
|
|
from six import with_metaclass
|
|
|
|
from .constants import WIZARD_TYPE_COOKIE, WIZARD_TYPE_SESSION
|
|
|
|
__title__ = 'fobi.dynamic'
|
|
__author__ = 'Artur Barseghyan <artur.barseghyan@gmail.com>'
|
|
__copyright__ = '2014-2019 Artur Barseghyan'
|
|
__license__ = 'GPL 2.0/LGPL 2.1'
|
|
__all__ = (
|
|
'assemble_form_class',
|
|
'assemble_form_wizard_class',
|
|
)
|
|
|
|
# ****************************************************************************
|
|
# ****************************************************************************
|
|
# **************************** Form generator ********************************
|
|
# ****************************************************************************
|
|
# ****************************************************************************
|
|
|
|
|
|
def assemble_form_class(form_entry,
|
|
base_class=BaseForm,
|
|
request=None,
|
|
origin=None,
|
|
origin_kwargs_update_func=None,
|
|
origin_return_func=None,
|
|
form_element_entries=None,
|
|
get_form_field_instances_kwargs={}):
|
|
"""Assemble a form class by given entry.
|
|
|
|
:param form_entry:
|
|
:param base_class:
|
|
:param django.http.HttpRequest request:
|
|
:param string origin:
|
|
:param callable origin_kwargs_update_func:
|
|
:param callable origin_return_func:
|
|
:param iterable form_element_entries: If given, used instead of
|
|
``form_entry.formelemententry_set.all`` (no additional database hit).
|
|
:param dict get_form_field_instances_kwargs: To be passed as **kwargs to
|
|
the :method:`get_form_field_instances_kwargs`.
|
|
"""
|
|
if form_element_entries is None:
|
|
form_element_entries = form_entry.formelemententry_set.all()
|
|
|
|
# DeclarativeFieldsMetaclass
|
|
class DeclarativeFieldsMetaclass(type):
|
|
"""Declarative fields meta class.
|
|
|
|
Copied from ``django.forms.forms.DeclarativeFieldsMetaclass``.
|
|
|
|
Metaclass that converts Field attributes to a dictionary called
|
|
`base_fields`, taking into account parent class 'base_fields' as well.
|
|
"""
|
|
|
|
def __new__(cls, name, bases, attrs):
|
|
"""New."""
|
|
base_fields = []
|
|
|
|
for creation_counter, form_element_entry \
|
|
in enumerate(form_element_entries):
|
|
plugin = form_element_entry.get_plugin(request=request)
|
|
|
|
# We simply make sure the plugin exists. We don't handle
|
|
# exceptions relate to the non-existent plugins here. They
|
|
# are instead handled in registry.
|
|
if plugin:
|
|
plugin_form_field_instances = \
|
|
plugin._get_form_field_instances(
|
|
form_element_entry=form_element_entry,
|
|
origin=origin,
|
|
kwargs_update_func=origin_kwargs_update_func,
|
|
return_func=origin_return_func,
|
|
extra={'counter': creation_counter},
|
|
request=request,
|
|
form_entry=form_entry,
|
|
form_element_entries=form_element_entries,
|
|
**get_form_field_instances_kwargs
|
|
)
|
|
for form_field_name, form_field_instance \
|
|
in plugin_form_field_instances:
|
|
base_fields.append(
|
|
(form_field_name, form_field_instance)
|
|
)
|
|
|
|
attrs['base_fields'] = OrderedDict(base_fields)
|
|
new_class = super(DeclarativeFieldsMetaclass, cls).__new__(
|
|
cls, name, bases, attrs
|
|
)
|
|
|
|
if 'media' not in attrs:
|
|
new_class.media = media_property(new_class)
|
|
|
|
return new_class
|
|
|
|
# DynamicForm
|
|
class DynamicForm(with_metaclass(DeclarativeFieldsMetaclass, base_class)):
|
|
"""Dynamically created form element plugin class."""
|
|
|
|
# Finally, return the DynamicForm
|
|
return DynamicForm
|
|
|
|
|
|
def assemble_form_wizard_class(form_wizard_entry,
|
|
base_class=SessionWizardView,
|
|
request=None,
|
|
origin=None,
|
|
origin_kwargs_update_func=None,
|
|
origin_return_func=None,
|
|
form_wizard_form_entries=None,
|
|
template_name=None):
|
|
"""Assemble form wizard class.
|
|
|
|
:param form_wizard_entry:
|
|
:param base_class:
|
|
:param request:
|
|
:param origin:
|
|
:param origin_kwargs_update_func:
|
|
:param origin_return_func:
|
|
:param form_wizard_form_entries:
|
|
:param template_name:
|
|
:return:
|
|
"""
|
|
|
|
if form_wizard_entry.wizard_type == WIZARD_TYPE_SESSION:
|
|
base_class = SessionWizardView
|
|
elif form_wizard_entry.wizard_type == WIZARD_TYPE_COOKIE:
|
|
base_class = CookieWizardView
|
|
elif not issubclass(base_class, WizardView):
|
|
base_class = SessionWizardView
|
|
|
|
if form_wizard_form_entries is None:
|
|
form_entries = [
|
|
form_wizard_form_entry.form_entry
|
|
for form_wizard_form_entry
|
|
in form_wizard_entry.formwizardformentry_set.all()
|
|
]
|
|
else:
|
|
form_entries = [
|
|
form_wizard_form_entry.form_entry
|
|
for form_wizard_form_entry
|
|
in form_wizard_form_entries
|
|
]
|
|
|
|
# DeclarativeFormsMetaclass
|
|
class DeclarativeFormsMetaclass(type):
|
|
"""Declarative forms meta class.
|
|
|
|
Copied from ``django.forms.forms.DeclarativeFieldsMetaclass``.
|
|
|
|
Metaclass that converts Forms attributes to a dictionary called
|
|
`form_list`, taking into account parent class 'form_list' as well.
|
|
"""
|
|
|
|
def __new__(cls, name, bases, attrs):
|
|
"""New.
|
|
|
|
Form list should be presented in the following way:
|
|
|
|
..code-block: python
|
|
|
|
named_contact_forms = (
|
|
('contactdata', ContactForm1),
|
|
('leavemessage', ContactForm2),
|
|
)
|
|
|
|
In the example above, the fist item of the tuple would be
|
|
the slug of the form included. The second one would be the
|
|
form class.
|
|
"""
|
|
form_list = []
|
|
|
|
for creation_counter, form_entry \
|
|
in enumerate(form_entries):
|
|
|
|
form_cls = assemble_form_class(
|
|
form_entry,
|
|
request=request
|
|
)
|
|
|
|
form_list.append(
|
|
(form_entry.slug, form_cls)
|
|
)
|
|
|
|
attrs['form_list'] = form_list
|
|
attrs['template_name'] = template_name
|
|
new_class = super(DeclarativeFormsMetaclass, cls).__new__(
|
|
cls, name, bases, attrs
|
|
)
|
|
|
|
# if 'media' not in attrs:
|
|
# new_class.media = media_property(new_class)
|
|
|
|
return new_class
|
|
|
|
# DynamicFormWizard
|
|
class DynamicFormWizard(with_metaclass(
|
|
DeclarativeFormsMetaclass, base_class)):
|
|
"""Dynamically created form wizard class."""
|
|
|
|
def done(self, form_list, **kwargs):
|
|
"""Done."""
|
|
# do_something_with_the_form_data(form_list)
|
|
redirect_url = reverse('fobi.form_wizard_entry_submitted',
|
|
[form_wizard_entry.slug])
|
|
return HttpResponseRedirect(redirect_url)
|
|
|
|
# Finally, return the dynamic wizard
|
|
return DynamicFormWizard
|