This is a library for creating multi-page wizards using z3c.form. Values are stored in a session until the wizard is finished.
Project description
Introduction
This library implements a simple z3c.form-based wizard. The wizard is composed of multiple steps. Each step is a form. Data is stored in a session until the user clicks the Finish button on the last step.
Wizard Step
A wizard step is a normal z3c.form form with a few additional features.
By default, the content accessed by this form will be a dictionary within the wizard’s session, with a key equal to the step’s prefix.
Additional attributes:
- wizard
The wizard this step is being used in.
- completed
Boolean indicating whether the user should be allowed to move on to the next step. Defaults to True. Override this with a property if you need custom logic.
Additional methods:
- applyChanges(data)
Saves changes from this step to its content (typically a PersistentDict in the wizard’s session.)
- load(context):
Loads the session data for this step based on a context.
- apply(context):
Updates a context based on the session data for this step.
Wizard
The wizard is also a form, with a list of steps and built-in logic for moving between those steps.
Class attributes. Override these to affect how the wizard behaves:
- steps
A sequence of step classes that will be instantiated when the wizard’s update method is called.
- sessionKey
Returns the unique session key used by this wizard instance. By default, this is a tuple of ‘collective.z3cform.wizard’ and the URL path to the wizard.
Attributes set during the update method:
- activeSteps
A sequence of wizard step instances.
- currentStep
The wizard step instance currently being displayed.
- currentIndex
The (0-based) index of the current step within the activeSteps sequence.
- session
The session where data for this wizard is persisted.
- onFirstStep
Boolean. True if the first step of the wizard is being displayed.
- onLastStep
Boolean. True if the last step of the wizard is being displayed.
- finished
Boolean. True if the wizard has been completed.
Methods:
- initialize()
Called the first time a wizard is viewed in a given session.
This method may be used to populate the session with data from some source.
The default implementation calls the loadSteps method.
- loadSteps(context)
Loads the wizard session data from a context.
The default implementation calls the ‘load’ method of each wizard step.
- finish()
Called when a wizard is successfully completed, after validation of the final step.
Use this method to carry out some actions based on the values that have been filled out during completion of the wizard.
The default implementation calls the applySteps method.
- applySteps(context)
Updates a context based on the wizard session data.
The default implementation calls the ‘apply’ method of each wizard step.
- sync()
Mark the session as having changed, to ensure that changes get persisted. This is required since we aren’t using a persistence-aware dictionary class for our session variables.
Compatibility
This package has been tested in Zope 2.10 with Plone 3.3.
It should be pretty easy to get it to work in other environments supported by z3c.form, such as Zope 3, but I’ll need someone familiar with those environments to tell me how sessions work there, for example.
Credits
This package is inspired by and based on the non-session-based z3c.form wizard included in the collective.singing package, which was implemented by Daniel Nouri.
Session support, miscellaneous improvements, and repackaging by David Glick.
Changelog
1.0b1 (xxxx-xx-xx)
Initial release
Example and tests
Define a wizard with three steps
To define a form that uses the wizard, we’ll need to define steps. These steps represent individual forms that are processed sequentially. Only when the last step is completed will the data be submitted through a user-defined method.
>>> from zope import schema >>> from z3c.form import field, form >>> from collective.z3cform.wizard import wizard>>> class StepOne(wizard.Step): ... prefix = 'one' ... fields = field.Fields( ... schema.Int(__name__='age', title=u"Age"))
By default, the steps will get/set values in the session. If we want to initialize these values or do something with them once the wizard is completed, we need to implement the load and apply methods for our step.
>>> from pprint import pprint >>> class StepTwo(wizard.Step): ... prefix = 'two' ... fields = field.Fields( ... schema.TextLine(__name__='name', title=u"Name", required=True)) ... ... def load(self, context): ... data = self.getContent() ... data['name'] = 'David' ... ... def apply(self, context): ... data = self.getContent() ... pprint('Name from step 2: %s' % data['name'])>>> class StepThree(wizard.Step): ... prefix = 'three' ... fields = field.Fields( ... schema.TextLine(__name__='color', title=u'Favorite Color', required=False))
We can now define our minimal wizard:
>>> class Wizard(wizard.Wizard): ... label = u"My silly wizard" ... steps = StepOne, StepTwo, StepThree
Render the form
Let’s render the form for the first time now:
>>> request = TestRequest() >>> wizard = Wizard(None, request) >>> print wizard() <style... <div class="form"> <form action="http://127.0.0.1" method="post"> <p class="discreet"></p> <div class="row"> <div class="field"> <label for="one-widgets-age"> <span>Age</span> </label>... <span class="fieldRequired" title="Required"> (Required) </span> <div class="widget"> <input type="text" id="one-widgets-age" name="one.widgets.age" class="text-widget required int-field" value="" /> </div> </div> </div> <hr /> <div class="wizard-buttons"> <div class="action"> <input type="submit" id="form-buttons-continue" name="form.buttons.continue" class="submit-widget button-field" value="Continue" /> </div> </div> </form> </div>
Submit with an error
Remember that our first step requires the age.
>>> request.form = { ... 'form.buttons.continue': u'Continue', ... } >>> wizard = Wizard(None, request) >>> print wizard() <... <div class="form"> ...There were errors... ...Required input is missing...
Submit the first step successfully
>>> request.form['one.widgets.age'] = u'27' >>> wizard = Wizard(None, request) >>> print wizard() <... <div class="form"> <form action="http://127.0.0.1" method="post"> <p class="discreet"></p> <div class="row"> <div class="field"> <label for="two-widgets-name"> <span>Name</span> </label> <span class="fieldRequired" title="Required"> (Required) </span> <div class="widget"> <input type="text" id="two-widgets-name" name="two.widgets.name" class="text-widget required textline-field" value="David" /> </div> </div> </div> <hr /> <div class="wizard-buttons"> <div class="action"> <input type="submit" id="form-buttons-back" name="form.buttons.back" class="submit-widget button-field" value="Back" /> </div> <div class="action"> <input type="submit" id="form-buttons-continue" name="form.buttons.continue" class="submit-widget button-field" value="Continue" /> </div> </div> </form> </div>
Submitting step two
Step two works similarly:
>>> request.form['two.widgets.name'] = u'David' >>> wizard = Wizard(None, request) >>> html = wizard() >>> 'three' in html, 'Finish' in html (True, True)
Step three: Slaying the dragon
Now let’s press the Finish button. We expect this to print out the value from step 2, thanks to the ‘apply’ method we implemented for that step.
Remembering that in our wizard, we implemented finish to print out the data that it receives. Here’s the finishing move:
>>> request.form['form.buttons.finish'] = u'Finish' >>> wizard = Wizard(None, request) >>> html = wizard() 'Name from step 2: David'>>> print html <... <div class="form"> <div class="portalMessage">Information submitted successfully.</div> </div>...
Real-world example
See the collective.megaphone package for a real-world use of this library.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Hashes for collective.z3cform.wizard-1.0b1.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 207d276ba62fc9a5eba2b93a9b65c0f1b0ffefa5816ab4f9bc5a0b9871add455 |
|
MD5 | 59a380fe58b4f2d779a81b478ddd15ba |
|
BLAKE2b-256 | 9c6b8140e9d333db882263457ff0678a889ef37e81648effa142b7cdf8714ff6 |