Opened 9 years ago

Closed 7 years ago

Last modified 7 years ago

#3218 closed enhancement (fixed)

[patch] django.contrib.formtools.wizard proposal

Reported by: Honza Král <Honza.Kral@…> Owned by: adrian
Component: contrib.formtools Version: master
Severity: normal Keywords: newforms wizard sprintsept14
Cc: Honza.Kral@…, nick.lane.au@…, larlet@…, jesse.lovelace@…, allandouglas@…, remco@…, matt.dorn@…, join.together@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

following the discussion
http://groups-beta.google.com/group/django-developers/browse_thread/thread/d500c47eb51353e3/2e61103c43fba506?

I have added some more flexibility and cleaned up the code a bit (and added comments ;) ).

Features:

  • just subclass the wizard.Wizard class, override the done() method and you are done - you can just point your urls.py to MyWizard( [list, of, newform, classes] ) and wait...
  • data from previous steps are stored in hidden fields and passed back and forth (do not try and use this for uploading files in any, but the last step of the form ! ), NO data is stored on the server
  • security hash is calculated once the form is validated ( thus you avoid validating each form every time and can detect manual tampering with the POST data)

If that's not enough you can (by overriding/extending some methods):

  • create the list of forms dynamically (you still have to supply at least one form, so that the wizard has something to start with) - do this in process_step() (just append to self.form_list ) -- see the last email for example
  • use a custom template name for every step ( get_template() )
  • override the rendering method for custom rendering ( render_template() )
  • override the mechanism that handles the step counter - by default that is in POST['wizard_step'] , but you can put it in your URL, GET or even session if you wish ( parse_params() )
  • provide extra_context (from urls.py, process_step(), parse_params() etc...)

The only thing that is pretty much hardcoded is the use of POST throughout the wizard.

I am using the code (not the newest version, but I only made cosmeticall changes since) for some time now and everything works.

Once I get some feedback and a few people try it out, I will put together some documentation.

Attachments (13)

wizard.py (7.5 KB) - added by Honza Král <Honza.Kral@…> 9 years ago.
wizard_20070111.py (7.8 KB) - added by Honza Král <Honza.Kral@…> 9 years ago.
updated version
wizard.2.py (8.3 KB) - added by Honza_Kral 8 years ago.
matching current trunk (6158)
wizard.3.py (8.1 KB) - added by Honza_Kral 8 years ago.
matching django's coding style
form_wizard_start_of_tests.diff (13.4 KB) - added by Øyvind Saltvik <oyvind@…> 8 years ago.
My test code so far
wizard.4.py (8.3 KB) - added by Honza_Kral 8 years ago.
validating all forms before invoking done()
form_wizard_start_of_tests.2.diff (12.1 KB) - added by Øyvind Saltvik <oyvind@…> 8 years ago.
Test so far, anyone else want to give it a go, i'm suffering from test blindness
wizard.5.py (8.5 KB) - added by Honza_Kral 8 years ago.
added current_step and step_count
form_wizard_start_of_tests_using_wizard.5.diff (13.3 KB) - added by Øyvind Saltvik <oyvind@…> 8 years ago.
Updated to Honza's latest code
form_wizard_hash_tests.diff (13.9 KB) - added by Øyvind Saltvik <oyvind@…> 8 years ago.
Test of hashes done
form_wizard_hash_tests_failed_hash_dynamic_form.diff (16.6 KB) - added by Øyvind Saltvik <oyvind@…> 8 years ago.
Added some extra tests
form_wizard.txt (3.2 KB) - added by mdorn 8 years ago.
Updated documentation, final.
form_wizard_with_tests_and_docs_r6199.diff (20.1 KB) - added by Øyvind Saltvik <oyvind@…> 8 years ago.
Complete patch for newforms-admin branch

Download all attachments as: .zip

Change History (43)

Changed 9 years ago by Honza Král <Honza.Kral@…>

comment:1 Changed 9 years ago by jl@…

Very nice Honza,
I'm already using it in a registration form.

What do you think about a method to navigate through the formlist with html inputs like [< Back] [ Next Step >]?
Or is it possible with current wizard.py (01/02/07)?

comment:2 Changed 9 years ago by Honza Král <Honza.Kral@…>

yes it is, you just press the back button, it will work, or you revert the step to a lower number... but these are all hacks, there is no currently supported way...

I have new version that allows the form to be pre-filled from the previous steps... I will attach it...

Changed 9 years ago by Honza Král <Honza.Kral@…>

updated version

comment:3 Changed 9 years ago by Jannis Leidel <jl@…>

thanks for the initial data function..
unfortunately I don't understand how to use it. could you give a small example like you did on the maillinglist?

regarding the navigational functionality with "back"- and "next"-form submit inputs:

I try to lower self.step within a subclass method "parse_params" by finding out if request.POST.get("navigation") is set (submit input html tag with the name "navigation") and decreasing self.step by 1. strangely it will just work if I decrease by 2 which then breaks the parsing of the template when I want to jump back to form 0 because it wants template wizard-1.html and not wizard0.html. I'm sure this is just an misunderstanding on my side. could you explain a little more?

comment:4 Changed 9 years ago by nervotrepka

  • Component changed from django.contrib.formtools to Unit test system
  • Severity changed from normal to blocker
  • Version changed from SVN to new-admin

5cb16d1ade0a My homepage vvv_5_1 vvv_5_1
vvv_5_2 vvv_5_2
vvv_5_3 vvv_5_3
vvv_5_4 vvv_5_4
vvv_5_5 vvv_5_5

comment:5 Changed 9 years ago by Collin Grady <cgrady@…>

  • Component changed from Unit test system to django.contrib.formtools
  • Severity changed from blocker to normal
  • Version changed from new-admin to SVN

comment:6 Changed 9 years ago by Honza Král <Honza.Kral@…>

  • Needs documentation set

comment:7 Changed 9 years ago by Simon G. <dev@…>

  • Triage Stage changed from Unreviewed to Design decision needed

comment:8 Changed 8 years ago by nick.lane.au@…

  • Cc nick.lane.au@… added

comment:9 Changed 8 years ago by anonymous

  • Cc larlet@… added

comment:10 Changed 8 years ago by anonymous

  • Cc jesse.lovelace@… added

comment:11 Changed 8 years ago by anonymous

  • Cc allandouglas@… added

comment:12 Changed 8 years ago by Honza_Kral

  • Owner changed from nobody to Honza_Kral

comment:13 Changed 8 years ago by david

There is an interesting snippet about that: http://www.djangosnippets.org/snippets/222/

comment:14 Changed 8 years ago by anonymous

  • Cc remco@… added

Changed 8 years ago by Honza_Kral

matching current trunk (6158)

comment:15 Changed 8 years ago by adrian

  • Triage Stage changed from Design decision needed to Accepted

This is a cool idea. Before we can check it in, though, it needs docs and tests.

comment:16 Changed 8 years ago by mdorn

  • Owner changed from Honza_Kral to mdorn
  • Status changed from new to assigned

working on docs and tests

comment:17 Changed 8 years ago by Øyvind Saltvik <oyvind@…>

  • Keywords sprintsept14 added

Changed 8 years ago by Honza_Kral

matching django's coding style

Changed 8 years ago by Øyvind Saltvik <oyvind@…>

My test code so far

Changed 8 years ago by Honza_Kral

validating all forms before invoking done()

Changed 8 years ago by Øyvind Saltvik <oyvind@…>

Test so far, anyone else want to give it a go, i'm suffering from test blindness

Changed 8 years ago by Honza_Kral

added current_step and step_count

Changed 8 years ago by Øyvind Saltvik <oyvind@…>

Updated to Honza's latest code

Changed 8 years ago by Øyvind Saltvik <oyvind@…>

Test of hashes done

Changed 8 years ago by Øyvind Saltvik <oyvind@…>

Added some extra tests

Changed 8 years ago by mdorn

Updated documentation, final.

comment:18 Changed 8 years ago by mdorn

  • Cc matt.dorn@… added
  • Owner changed from mdorn to Honza_Kral
  • Status changed from assigned to new

Documentation finished, reassigning to Honza, so he can double-check before moving to check-in

comment:19 Changed 8 years ago by mdorn

  • Needs documentation unset

Changed 8 years ago by Øyvind Saltvik <oyvind@…>

Complete patch for newforms-admin branch

comment:20 follow-up: Changed 8 years ago by jstritar@…

Since the previous step's data is kept as POST parameters, there isn't a nice way to go back to a previous step (other than the back button). I think something like this is an important usability feature (think of a checkout process where you can click previous steps if you made a mistake).

Example:

| 1 | 2 | 3 | 4 |

I am on step 4. I click the 2, loading the 2nd step with the data I originally entered.

comment:21 in reply to: ↑ 20 Changed 8 years ago by Honza_Kral

Replying to jstritar@gmail.com:

Since the previous step's data is kept as POST parameters, there isn't a nice way to go back to a previous step (other than the back button). I think something like this is an important usability feature (think of a checkout process where you can click previous steps if you made a mistake).

Example:

| 1 | 2 | 3 | 4 |

I am on step 4. I click the 2, loading the 2nd step with the data I originally entered.

I thought that wouldn't be the common usage, but you can achieve that via overriding the parse_params method, you can derive self.step from URL, GET or any other means you feel like...

comment:22 follow-up: Changed 8 years ago by Jon Stritar <jstritar@…>

You'd be able to pass the step via a URL or GET parameter, but the Forms up to and including that step wouldn't have any data (since there wasn't a POST).

comment:23 in reply to: ↑ 22 ; follow-up: Changed 8 years ago by Honza_Kral

Replying to Jon Stritar <jstritar@gmail.com>:

You'd be able to pass the step via a URL or GET parameter, but the Forms up to and including that step wouldn't have any data (since there wasn't a POST).

true, haven't actually thought it through this far... I guess the only option is to have the form post the data with the appropriate step value - you won't avoid a form or some javascript...

I a generally opposed to the idea of storing the data on server-side it doesn't make much sense, adds a lot of additional complexity and dependency on sessions and/or some other form of storing the data...

comment:24 in reply to: ↑ 23 ; follow-up: Changed 8 years ago by anonymous

Replying to Honza_Kral:

I a generally opposed to the idea of storing the data on server-side it doesn't make much sense, adds a lot of additional complexity and dependency on sessions and/or some other form of storing the data...

I think what we are talking about here is state, and isn't maintaining state exactly what sessions are for in an otherwise stateless protocol? I know that it is more elegant to minimize dependancies, but depending on the sessions framework is justified here imho.

comment:25 in reply to: ↑ 24 Changed 8 years ago by remco@…

oops didn't want to show as an anonymous coward :)

comment:26 Changed 8 years ago by anonymous

what is the status of this bug?

I tested the diffs with 0.97-pre-SVN-6971 and it didn't work for me. :(

comment:27 Changed 7 years ago by adrian

  • Owner changed from Honza_Kral to adrian
  • Status changed from new to assigned

I have an immediate need for this for a project, so I'll take the lead on reviewing and checking it in.

comment:28 Changed 7 years ago by adrian

  • Resolution set to fixed
  • Status changed from assigned to closed

(In [7236]) Fixed #3218 -- Implemented django.contrib.formtools.wizard. Thanks, Honza and Oyvind. Note that there are no docs yet

comment:29 follow-up: Changed 7 years ago by anonymous

  • Cc join.together@… added

I know a lot of people have cc'd this, so i'll ask this here before making a ticket out of it in the hopes that someone can answer.

When calculating the hash, why dose it use unclean data? I've found a bug that causes Booleanfields that are set to false to erroneously cause the hash tst

(On the first pass, the value for the field is calculated to be (empty string), but the next time you try to submit something it's somehow False now, so the data is different than it was previously so the test fails and you have to start over.)

I would gladly write a patch that has it pull the data to be hashed from form.cleaned data, but before I do is there a reason why it doesn't already do that?

comment:30 in reply to: ↑ 29 Changed 7 years ago by Honza_Kral

Replying to anonymous:

I know a lot of people have cc'd this, so i'll ask this here before making a ticket out of it in the hopes that someone can answer.

When calculating the hash, why dose it use unclean data?

because than we can make tests without doing the clean(), which may be an expensive operation... so we don't have to validate every data on every pass...

Note: See TracTickets for help on using tickets.
Back to Top