app/django/contrib/formtools/wizard.py
changeset 323 ff1a9aa48cfd
parent 54 03e267d67478
equal deleted inserted replaced
322:6641e941ef1e 323:ff1a9aa48cfd
     2 FormWizard class -- implements a multi-page form, validating between each
     2 FormWizard class -- implements a multi-page form, validating between each
     3 step and storing the form's state as HTML hidden fields so that no state is
     3 step and storing the form's state as HTML hidden fields so that no state is
     4 stored on the server side.
     4 stored on the server side.
     5 """
     5 """
     6 
     6 
     7 from django import newforms as forms
     7 import cPickle as pickle
       
     8 
       
     9 from django import forms
     8 from django.conf import settings
    10 from django.conf import settings
     9 from django.http import Http404
    11 from django.http import Http404
    10 from django.shortcuts import render_to_response
    12 from django.shortcuts import render_to_response
    11 from django.template.context import RequestContext
    13 from django.template.context import RequestContext
    12 import cPickle as pickle
    14 from django.utils.hashcompat import md5_constructor
    13 import md5
    15 from django.utils.translation import ugettext_lazy as _
       
    16 from django.contrib.formtools.utils import security_hash
    14 
    17 
    15 class FormWizard(object):
    18 class FormWizard(object):
    16     # Dictionary of extra template context variables.
    19     # Dictionary of extra template context variables.
    17     extra_context = {}
    20     extra_context = {}
    18 
    21 
    88                 return self.done(request, final_form_list)
    91                 return self.done(request, final_form_list)
    89 
    92 
    90             # Otherwise, move along to the next step.
    93             # Otherwise, move along to the next step.
    91             else:
    94             else:
    92                 form = self.get_form(next_step)
    95                 form = self.get_form(next_step)
    93                 current_step = next_step
    96                 self.step = current_step = next_step
    94 
    97 
    95         return self.render(form, request, current_step)
    98         return self.render(form, request, current_step)
    96 
    99 
    97     def render(self, form, request, step, context=None):
   100     def render(self, form, request, step, context=None):
    98         "Renders the given Form object, returning an HttpResponse."
   101         "Renders the given Form object, returning an HttpResponse."
   122         valid.
   125         valid.
   123 
   126 
   124         This default implementation simply renders the form for the given step,
   127         This default implementation simply renders the form for the given step,
   125         but subclasses may want to display an error message, etc.
   128         but subclasses may want to display an error message, etc.
   126         """
   129         """
   127         return self.render(self.get_form(step), request, step, context={'wizard_error': 'We apologize, but your form has expired. Please continue filling out the form from this page.'})
   130         return self.render(self.get_form(step), request, step, context={'wizard_error': _('We apologize, but your form has expired. Please continue filling out the form from this page.')})
   128 
   131 
   129     def render_revalidation_failure(self, request, step, form):
   132     def render_revalidation_failure(self, request, step, form):
   130         """
   133         """
   131         Hook for rendering a template if final revalidation failed.
   134         Hook for rendering a template if final revalidation failed.
   132 
   135 
   137 
   140 
   138     def security_hash(self, request, form):
   141     def security_hash(self, request, form):
   139         """
   142         """
   140         Calculates the security hash for the given HttpRequest and Form instances.
   143         Calculates the security hash for the given HttpRequest and Form instances.
   141 
   144 
   142         This creates a list of the form field names/values in a deterministic
       
   143         order, pickles the result with the SECRET_KEY setting and takes an md5
       
   144         hash of that.
       
   145 
       
   146         Subclasses may want to take into account request-specific information,
   145         Subclasses may want to take into account request-specific information,
   147         such as the IP address.
   146         such as the IP address.
   148         """
   147         """
   149         data = [(bf.name, bf.data or '') for bf in form] + [settings.SECRET_KEY]
   148         return security_hash(request, form)
   150         # Use HIGHEST_PROTOCOL because it's the most efficient. It requires
       
   151         # Python 2.3, but Django requires 2.3 anyway, so that's OK.
       
   152         pickled = pickle.dumps(data, protocol=pickle.HIGHEST_PROTOCOL)
       
   153         return md5.new(pickled).hexdigest()
       
   154 
   149 
   155     def determine_step(self, request, *args, **kwargs):
   150     def determine_step(self, request, *args, **kwargs):
   156         """
   151         """
   157         Given the request object and whatever *args and **kwargs were passed to
   152         Given the request object and whatever *args and **kwargs were passed to
   158         __call__(), returns the current step (which is zero-based).
   153         __call__(), returns the current step (which is zero-based).
   207                           through the "safe" template filter, to prevent
   202                           through the "safe" template filter, to prevent
   208                           auto-escaping, because it's raw HTML.
   203                           auto-escaping, because it's raw HTML.
   209         """
   204         """
   210         context = context or {}
   205         context = context or {}
   211         context.update(self.extra_context)
   206         context.update(self.extra_context)
   212         return render_to_response(self.get_template(self.step), dict(context,
   207         return render_to_response(self.get_template(step), dict(context,
   213             step_field=self.step_field_name,
   208             step_field=self.step_field_name,
   214             step0=step,
   209             step0=step,
   215             step=step + 1,
   210             step=step + 1,
   216             step_count=self.num_steps(),
   211             step_count=self.num_steps(),
   217             form=form,
   212             form=form,