summaryrefslogtreecommitdiff
path: root/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py')
-rw-r--r--lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py730
1 files changed, 0 insertions, 730 deletions
diff --git a/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py b/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py
deleted file mode 100644
index 494d87a..0000000
--- a/lib/python2.7/site-packages/django/contrib/formtools/wizard/views.py
+++ /dev/null
@@ -1,730 +0,0 @@
-import re
-
-from django import forms
-from django.shortcuts import redirect
-from django.core.urlresolvers import reverse
-from django.forms import formsets, ValidationError
-from django.views.generic import TemplateView
-from django.utils.datastructures import SortedDict
-from django.utils.decorators import classonlymethod
-from django.utils.translation import ugettext as _
-from django.utils import six
-
-from django.contrib.formtools.wizard.storage import get_storage
-from django.contrib.formtools.wizard.storage.exceptions import NoFileStorageConfigured
-from django.contrib.formtools.wizard.forms import ManagementForm
-
-
-def normalize_name(name):
- """
- Converts camel-case style names into underscore seperated words. Example::
-
- >>> normalize_name('oneTwoThree')
- 'one_two_three'
- >>> normalize_name('FourFiveSix')
- 'four_five_six'
-
- """
- new = re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', '_\\1', name)
- return new.lower().strip('_')
-
-class StepsHelper(object):
-
- def __init__(self, wizard):
- self._wizard = wizard
-
- def __dir__(self):
- return self.all
-
- def __len__(self):
- return self.count
-
- def __repr__(self):
- return '<StepsHelper for %s (steps: %s)>' % (self._wizard, self.all)
-
- @property
- def all(self):
- "Returns the names of all steps/forms."
- return list(self._wizard.get_form_list())
-
- @property
- def count(self):
- "Returns the total number of steps/forms in this the wizard."
- return len(self.all)
-
- @property
- def current(self):
- """
- Returns the current step. If no current step is stored in the
- storage backend, the first step will be returned.
- """
- return self._wizard.storage.current_step or self.first
-
- @property
- def first(self):
- "Returns the name of the first step."
- return self.all[0]
-
- @property
- def last(self):
- "Returns the name of the last step."
- return self.all[-1]
-
- @property
- def next(self):
- "Returns the next step."
- return self._wizard.get_next_step()
-
- @property
- def prev(self):
- "Returns the previous step."
- return self._wizard.get_prev_step()
-
- @property
- def index(self):
- "Returns the index for the current step."
- return self._wizard.get_step_index()
-
- @property
- def step0(self):
- return int(self.index)
-
- @property
- def step1(self):
- return int(self.index) + 1
-
-
-class WizardView(TemplateView):
- """
- The WizardView is used to create multi-page forms and handles all the
- storage and validation stuff. The wizard is based on Django's generic
- class based views.
- """
- storage_name = None
- form_list = None
- initial_dict = None
- instance_dict = None
- condition_dict = None
- template_name = 'formtools/wizard/wizard_form.html'
-
- def __repr__(self):
- return '<%s: forms: %s>' % (self.__class__.__name__, self.form_list)
-
- @classonlymethod
- def as_view(cls, *args, **kwargs):
- """
- This method is used within urls.py to create unique wizardview
- instances for every request. We need to override this method because
- we add some kwargs which are needed to make the wizardview usable.
- """
- initkwargs = cls.get_initkwargs(*args, **kwargs)
- return super(WizardView, cls).as_view(**initkwargs)
-
- @classmethod
- def get_initkwargs(cls, form_list=None, initial_dict=None,
- instance_dict=None, condition_dict=None, *args, **kwargs):
- """
- Creates a dict with all needed parameters for the form wizard instances.
-
- * `form_list` - is a list of forms. The list entries can be single form
- classes or tuples of (`step_name`, `form_class`). If you pass a list
- of forms, the wizardview will convert the class list to
- (`zero_based_counter`, `form_class`). This is needed to access the
- form for a specific step.
- * `initial_dict` - contains a dictionary of initial data dictionaries.
- The key should be equal to the `step_name` in the `form_list` (or
- the str of the zero based counter - if no step_names added in the
- `form_list`)
- * `instance_dict` - contains a dictionary whose values are model
- instances if the step is based on a ``ModelForm`` and querysets if
- the step is based on a ``ModelFormSet``. The key should be equal to
- the `step_name` in the `form_list`. Same rules as for `initial_dict`
- apply.
- * `condition_dict` - contains a dictionary of boolean values or
- callables. If the value of for a specific `step_name` is callable it
- will be called with the wizardview instance as the only argument.
- If the return value is true, the step's form will be used.
- """
-
- kwargs.update({
- 'initial_dict': initial_dict or kwargs.pop('initial_dict',
- getattr(cls, 'initial_dict', None)) or {},
- 'instance_dict': instance_dict or kwargs.pop('instance_dict',
- getattr(cls, 'instance_dict', None)) or {},
- 'condition_dict': condition_dict or kwargs.pop('condition_dict',
- getattr(cls, 'condition_dict', None)) or {}
- })
-
- form_list = form_list or kwargs.pop('form_list',
- getattr(cls, 'form_list', None)) or []
-
- computed_form_list = SortedDict()
-
- assert len(form_list) > 0, 'at least one form is needed'
-
- # walk through the passed form list
- for i, form in enumerate(form_list):
- if isinstance(form, (list, tuple)):
- # if the element is a tuple, add the tuple to the new created
- # sorted dictionary.
- computed_form_list[six.text_type(form[0])] = form[1]
- else:
- # if not, add the form with a zero based counter as unicode
- computed_form_list[six.text_type(i)] = form
-
- # walk through the new created list of forms
- for form in six.itervalues(computed_form_list):
- if issubclass(form, formsets.BaseFormSet):
- # if the element is based on BaseFormSet (FormSet/ModelFormSet)
- # we need to override the form variable.
- form = form.form
- # check if any form contains a FileField, if yes, we need a
- # file_storage added to the wizardview (by subclassing).
- for field in six.itervalues(form.base_fields):
- if (isinstance(field, forms.FileField) and
- not hasattr(cls, 'file_storage')):
- raise NoFileStorageConfigured(
- "You need to define 'file_storage' in your "
- "wizard view in order to handle file uploads.")
-
- # build the kwargs for the wizardview instances
- kwargs['form_list'] = computed_form_list
- return kwargs
-
- def get_prefix(self, *args, **kwargs):
- # TODO: Add some kind of unique id to prefix
- return normalize_name(self.__class__.__name__)
-
- def get_form_list(self):
- """
- This method returns a form_list based on the initial form list but
- checks if there is a condition method/value in the condition_list.
- If an entry exists in the condition list, it will call/read the value
- and respect the result. (True means add the form, False means ignore
- the form)
-
- The form_list is always generated on the fly because condition methods
- could use data from other (maybe previous forms).
- """
- form_list = SortedDict()
- for form_key, form_class in six.iteritems(self.form_list):
- # try to fetch the value from condition list, by default, the form
- # gets passed to the new list.
- condition = self.condition_dict.get(form_key, True)
- if callable(condition):
- # call the value if needed, passes the current instance.
- condition = condition(self)
- if condition:
- form_list[form_key] = form_class
- return form_list
-
- def dispatch(self, request, *args, **kwargs):
- """
- This method gets called by the routing engine. The first argument is
- `request` which contains a `HttpRequest` instance.
- The request is stored in `self.request` for later use. The storage
- instance is stored in `self.storage`.
-
- After processing the request using the `dispatch` method, the
- response gets updated by the storage engine (for example add cookies).
- """
- # add the storage engine to the current wizardview instance
- self.prefix = self.get_prefix(*args, **kwargs)
- self.storage = get_storage(self.storage_name, self.prefix, request,
- getattr(self, 'file_storage', None))
- self.steps = StepsHelper(self)
- response = super(WizardView, self).dispatch(request, *args, **kwargs)
-
- # update the response (e.g. adding cookies)
- self.storage.update_response(response)
- return response
-
- def get(self, request, *args, **kwargs):
- """
- This method handles GET requests.
-
- If a GET request reaches this point, the wizard assumes that the user
- just starts at the first step or wants to restart the process.
- The data of the wizard will be resetted before rendering the first step.
- """
- self.storage.reset()
-
- # reset the current step to the first step.
- self.storage.current_step = self.steps.first
- return self.render(self.get_form())
-
- def post(self, *args, **kwargs):
- """
- This method handles POST requests.
-
- The wizard will render either the current step (if form validation
- wasn't successful), the next step (if the current step was stored
- successful) or the done view (if no more steps are available)
- """
- # Look for a wizard_goto_step element in the posted data which
- # contains a valid step name. If one was found, render the requested
- # form. (This makes stepping back a lot easier).
- wizard_goto_step = self.request.POST.get('wizard_goto_step', None)
- if wizard_goto_step and wizard_goto_step in self.get_form_list():
- return self.render_goto_step(wizard_goto_step)
-
- # Check if form was refreshed
- management_form = ManagementForm(self.request.POST, prefix=self.prefix)
- if not management_form.is_valid():
- raise ValidationError(
- _('ManagementForm data is missing or has been tampered.'),
- code='missing_management_form',
- )
-
- form_current_step = management_form.cleaned_data['current_step']
- if (form_current_step != self.steps.current and
- self.storage.current_step is not None):
- # form refreshed, change current step
- self.storage.current_step = form_current_step
-
- # get the form for the current step
- form = self.get_form(data=self.request.POST, files=self.request.FILES)
-
- # and try to validate
- if form.is_valid():
- # if the form is valid, store the cleaned data and files.
- self.storage.set_step_data(self.steps.current, self.process_step(form))
- self.storage.set_step_files(self.steps.current, self.process_step_files(form))
-
- # check if the current step is the last step
- if self.steps.current == self.steps.last:
- # no more steps, render done view
- return self.render_done(form, **kwargs)
- else:
- # proceed to the next step
- return self.render_next_step(form)
- return self.render(form)
-
- def render_next_step(self, form, **kwargs):
- """
- This method gets called when the next step/form should be rendered.
- `form` contains the last/current form.
- """
- # get the form instance based on the data from the storage backend
- # (if available).
- next_step = self.steps.next
- new_form = self.get_form(next_step,
- data=self.storage.get_step_data(next_step),
- files=self.storage.get_step_files(next_step))
-
- # change the stored current step
- self.storage.current_step = next_step
- return self.render(new_form, **kwargs)
-
- def render_goto_step(self, goto_step, **kwargs):
- """
- This method gets called when the current step has to be changed.
- `goto_step` contains the requested step to go to.
- """
- self.storage.current_step = goto_step
- form = self.get_form(
- data=self.storage.get_step_data(self.steps.current),
- files=self.storage.get_step_files(self.steps.current))
- return self.render(form)
-
- def render_done(self, form, **kwargs):
- """
- This method gets called when all forms passed. The method should also
- re-validate all steps to prevent manipulation. If any form don't
- validate, `render_revalidation_failure` should get called.
- If everything is fine call `done`.
- """
- final_form_list = []
- # walk through the form list and try to validate the data again.
- for form_key in self.get_form_list():
- form_obj = self.get_form(step=form_key,
- data=self.storage.get_step_data(form_key),
- files=self.storage.get_step_files(form_key))
- if not form_obj.is_valid():
- return self.render_revalidation_failure(form_key, form_obj, **kwargs)
- final_form_list.append(form_obj)
-
- # render the done view and reset the wizard before returning the
- # response. This is needed to prevent from rendering done with the
- # same data twice.
- done_response = self.done(final_form_list, **kwargs)
- self.storage.reset()
- return done_response
-
- def get_form_prefix(self, step=None, form=None):
- """
- Returns the prefix which will be used when calling the actual form for
- the given step. `step` contains the step-name, `form` the form which
- will be called with the returned prefix.
-
- If no step is given, the form_prefix will determine the current step
- automatically.
- """
- if step is None:
- step = self.steps.current
- return str(step)
-
- def get_form_initial(self, step):
- """
- Returns a dictionary which will be passed to the form for `step`
- as `initial`. If no initial data was provied while initializing the
- form wizard, a empty dictionary will be returned.
- """
- return self.initial_dict.get(step, {})
-
- def get_form_instance(self, step):
- """
- Returns a object which will be passed to the form for `step`
- as `instance`. If no instance object was provied while initializing
- the form wizard, None will be returned.
- """
- return self.instance_dict.get(step, None)
-
- def get_form_kwargs(self, step=None):
- """
- Returns the keyword arguments for instantiating the form
- (or formset) on the given step.
- """
- return {}
-
- def get_form(self, step=None, data=None, files=None):
- """
- Constructs the form for a given `step`. If no `step` is defined, the
- current step will be determined automatically.
-
- The form will be initialized using the `data` argument to prefill the
- new form. If needed, instance or queryset (for `ModelForm` or
- `ModelFormSet`) will be added too.
- """
- if step is None:
- step = self.steps.current
- # prepare the kwargs for the form instance.
- kwargs = self.get_form_kwargs(step)
- kwargs.update({
- 'data': data,
- 'files': files,
- 'prefix': self.get_form_prefix(step, self.form_list[step]),
- 'initial': self.get_form_initial(step),
- })
- if issubclass(self.form_list[step], forms.ModelForm):
- # If the form is based on ModelForm, add instance if available
- # and not previously set.
- kwargs.setdefault('instance', self.get_form_instance(step))
- elif issubclass(self.form_list[step], forms.models.BaseModelFormSet):
- # If the form is based on ModelFormSet, add queryset if available
- # and not previous set.
- kwargs.setdefault('queryset', self.get_form_instance(step))
- return self.form_list[step](**kwargs)
-
- def process_step(self, form):
- """
- This method is used to postprocess the form data. By default, it
- returns the raw `form.data` dictionary.
- """
- return self.get_form_step_data(form)
-
- def process_step_files(self, form):
- """
- This method is used to postprocess the form files. By default, it
- returns the raw `form.files` dictionary.
- """
- return self.get_form_step_files(form)
-
- def render_revalidation_failure(self, step, form, **kwargs):
- """
- Gets called when a form doesn't validate when rendering the done
- view. By default, it changes the current step to failing forms step
- and renders the form.
- """
- self.storage.current_step = step
- return self.render(form, **kwargs)
-
- def get_form_step_data(self, form):
- """
- Is used to return the raw form data. You may use this method to
- manipulate the data.
- """
- return form.data
-
- def get_form_step_files(self, form):
- """
- Is used to return the raw form files. You may use this method to
- manipulate the data.
- """
- return form.files
-
- def get_all_cleaned_data(self):
- """
- Returns a merged dictionary of all step cleaned_data dictionaries.
- If a step contains a `FormSet`, the key will be prefixed with
- 'formset-' and contain a list of the formset cleaned_data dictionaries.
- """
- cleaned_data = {}
- for form_key in self.get_form_list():
- form_obj = self.get_form(
- step=form_key,
- data=self.storage.get_step_data(form_key),
- files=self.storage.get_step_files(form_key)
- )
- if form_obj.is_valid():
- if isinstance(form_obj.cleaned_data, (tuple, list)):
- cleaned_data.update({
- 'formset-%s' % form_key: form_obj.cleaned_data
- })
- else:
- cleaned_data.update(form_obj.cleaned_data)
- return cleaned_data
-
- def get_cleaned_data_for_step(self, step):
- """
- Returns the cleaned data for a given `step`. Before returning the
- cleaned data, the stored values are revalidated through the form.
- If the data doesn't validate, None will be returned.
- """
- if step in self.form_list:
- form_obj = self.get_form(step=step,
- data=self.storage.get_step_data(step),
- files=self.storage.get_step_files(step))
- if form_obj.is_valid():
- return form_obj.cleaned_data
- return None
-
- def get_next_step(self, step=None):
- """
- Returns the next step after the given `step`. If no more steps are
- available, None will be returned. If the `step` argument is None, the
- current step will be determined automatically.
- """
- if step is None:
- step = self.steps.current
- form_list = self.get_form_list()
- key = form_list.keyOrder.index(step) + 1
- if len(form_list.keyOrder) > key:
- return form_list.keyOrder[key]
- return None
-
- def get_prev_step(self, step=None):
- """
- Returns the previous step before the given `step`. If there are no
- steps available, None will be returned. If the `step` argument is
- None, the current step will be determined automatically.
- """
- if step is None:
- step = self.steps.current
- form_list = self.get_form_list()
- key = form_list.keyOrder.index(step) - 1
- if key >= 0:
- return form_list.keyOrder[key]
- return None
-
- def get_step_index(self, step=None):
- """
- Returns the index for the given `step` name. If no step is given,
- the current step will be used to get the index.
- """
- if step is None:
- step = self.steps.current
- return self.get_form_list().keyOrder.index(step)
-
- def get_context_data(self, form, **kwargs):
- """
- Returns the template context for a step. You can overwrite this method
- to add more data for all or some steps. This method returns a
- dictionary containing the rendered form step. Available template
- context variables are:
-
- * all extra data stored in the storage backend
- * `wizard` - a dictionary representation of the wizard instance
-
- Example:
-
- .. code-block:: python
-
- class MyWizard(WizardView):
- def get_context_data(self, form, **kwargs):
- context = super(MyWizard, self).get_context_data(form=form, **kwargs)
- if self.steps.current == 'my_step_name':
- context.update({'another_var': True})
- return context
- """
- context = super(WizardView, self).get_context_data(form=form, **kwargs)
- context.update(self.storage.extra_data)
- context['wizard'] = {
- 'form': form,
- 'steps': self.steps,
- 'management_form': ManagementForm(prefix=self.prefix, initial={
- 'current_step': self.steps.current,
- }),
- }
- return context
-
- def render(self, form=None, **kwargs):
- """
- Returns a ``HttpResponse`` containing all needed context data.
- """
- form = form or self.get_form()
- context = self.get_context_data(form=form, **kwargs)
- return self.render_to_response(context)
-
- def done(self, form_list, **kwargs):
- """
- This method must be overridden by a subclass to process to form data
- after processing all steps.
- """
- raise NotImplementedError("Your %s class has not defined a done() "
- "method, which is required." % self.__class__.__name__)
-
-
-class SessionWizardView(WizardView):
- """
- A WizardView with pre-configured SessionStorage backend.
- """
- storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage'
-
-
-class CookieWizardView(WizardView):
- """
- A WizardView with pre-configured CookieStorage backend.
- """
- storage_name = 'django.contrib.formtools.wizard.storage.cookie.CookieStorage'
-
-
-class NamedUrlWizardView(WizardView):
- """
- A WizardView with URL named steps support.
- """
- url_name = None
- done_step_name = None
-
- @classmethod
- def get_initkwargs(cls, *args, **kwargs):
- """
- We require a url_name to reverse URLs later. Additionally users can
- pass a done_step_name to change the URL name of the "done" view.
- """
- assert 'url_name' in kwargs, 'URL name is needed to resolve correct wizard URLs'
- extra_kwargs = {
- 'done_step_name': kwargs.pop('done_step_name', 'done'),
- 'url_name': kwargs.pop('url_name'),
- }
- initkwargs = super(NamedUrlWizardView, cls).get_initkwargs(*args, **kwargs)
- initkwargs.update(extra_kwargs)
-
- assert initkwargs['done_step_name'] not in initkwargs['form_list'], \
- 'step name "%s" is reserved for "done" view' % initkwargs['done_step_name']
- return initkwargs
-
- def get_step_url(self, step):
- return reverse(self.url_name, kwargs={'step': step})
-
- def get(self, *args, **kwargs):
- """
- This renders the form or, if needed, does the http redirects.
- """
- step_url = kwargs.get('step', None)
- if step_url is None:
- if 'reset' in self.request.GET:
- self.storage.reset()
- self.storage.current_step = self.steps.first
- if self.request.GET:
- query_string = "?%s" % self.request.GET.urlencode()
- else:
- query_string = ""
- return redirect(self.get_step_url(self.steps.current)
- + query_string)
-
- # is the current step the "done" name/view?
- elif step_url == self.done_step_name:
- last_step = self.steps.last
- return self.render_done(self.get_form(step=last_step,
- data=self.storage.get_step_data(last_step),
- files=self.storage.get_step_files(last_step)
- ), **kwargs)
-
- # is the url step name not equal to the step in the storage?
- # if yes, change the step in the storage (if name exists)
- elif step_url == self.steps.current:
- # URL step name and storage step name are equal, render!
- return self.render(self.get_form(
- data=self.storage.current_step_data,
- files=self.storage.current_step_files,
- ), **kwargs)
-
- elif step_url in self.get_form_list():
- self.storage.current_step = step_url
- return self.render(self.get_form(
- data=self.storage.current_step_data,
- files=self.storage.current_step_files,
- ), **kwargs)
-
- # invalid step name, reset to first and redirect.
- else:
- self.storage.current_step = self.steps.first
- return redirect(self.get_step_url(self.steps.first))
-
- def post(self, *args, **kwargs):
- """
- Do a redirect if user presses the prev. step button. The rest of this
- is super'd from WizardView.
- """
- wizard_goto_step = self.request.POST.get('wizard_goto_step', None)
- if wizard_goto_step and wizard_goto_step in self.get_form_list():
- return self.render_goto_step(wizard_goto_step)
- return super(NamedUrlWizardView, self).post(*args, **kwargs)
-
- def get_context_data(self, form, **kwargs):
- """
- NamedUrlWizardView provides the url_name of this wizard in the context
- dict `wizard`.
- """
- context = super(NamedUrlWizardView, self).get_context_data(form=form, **kwargs)
- context['wizard']['url_name'] = self.url_name
- return context
-
- def render_next_step(self, form, **kwargs):
- """
- When using the NamedUrlWizardView, we have to redirect to update the
- browser's URL to match the shown step.
- """
- next_step = self.get_next_step()
- self.storage.current_step = next_step
- return redirect(self.get_step_url(next_step))
-
- def render_goto_step(self, goto_step, **kwargs):
- """
- This method gets called when the current step has to be changed.
- `goto_step` contains the requested step to go to.
- """
- self.storage.current_step = goto_step
- return redirect(self.get_step_url(goto_step))
-
- def render_revalidation_failure(self, failed_step, form, **kwargs):
- """
- When a step fails, we have to redirect the user to the first failing
- step.
- """
- self.storage.current_step = failed_step
- return redirect(self.get_step_url(failed_step))
-
- def render_done(self, form, **kwargs):
- """
- When rendering the done view, we have to redirect first (if the URL
- name doesn't fit).
- """
- if kwargs.get('step', None) != self.done_step_name:
- return redirect(self.get_step_url(self.done_step_name))
- return super(NamedUrlWizardView, self).render_done(form, **kwargs)
-
-
-class NamedUrlSessionWizardView(NamedUrlWizardView):
- """
- A NamedUrlWizardView with pre-configured SessionStorage backend.
- """
- storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage'
-
-
-class NamedUrlCookieWizardView(NamedUrlWizardView):
- """
- A NamedUrlFormWizard with pre-configured CookieStorageBackend.
- """
- storage_name = 'django.contrib.formtools.wizard.storage.cookie.CookieStorage'