I need help understanding an issue with SQLFORM.factory ( in the context of a form wizard )

131 views
Skip to first unread message

Don_X

unread,
Aug 21, 2012, 12:32:09 AM8/21/12
to web...@googlegroups.com
Hello all !
In order for one to successfully manipulate and/or modify some snippets of code, one needs to understand fully what these snippets of codes do in the context they are used and placed ! ( off course !!! )

There is something that escapes me ... or that I do not fully comprehend ! ... and hopefully, one of you reading this post, will enlighten me !

First of all, let me explain what my objectives are, how I am approaching it :
I have 3 tables, and my objective is to present the future visitor with a form wizard in order to fill out these 3 tables by using SQLFORM.factory ! ( with about 17 different fields in total )
putting it all on one page is simple ! but does not look good  ! I much prefer the form wizard approach
like the one on this link :
https://github.com/mdipierro/web2py-recipes-source/raw/master/apps/04_advanced_forms/web2py.app.form_wizard.w2p

I have learned that SQLFORM.factory can be used without the need to mention the related table name, it can work with only the fields needed in order to create the form 
so that way, multiple tables can be put on one single form page and after submission and validation, we insert the values of these fields in their appropriate tables and the trick is done ! it works well for one page form !

I have also learned that we can use the table_name attribute ! ( I will return on that later ) !

In the form wizard, there is that line of code within the form wizard example ( in the controller )

def wizard():
   STEPS
= {0: ('field1','field2'), # fields for 1st page
     
1: ('field3','field4'), # fields for 2nd page
     
2: ('field5,''field6'), # fields for 3rd page
     
3: URL('done')}         # url when wizard completed

   step
= int(request.args(0) or 0)
   
if not step in STEPS: redirect(URL(args=0))
   fields
= STEPS[step]
   
if step==0:
      session
.wizard = {}
   
if isinstance(fields,tuple):
      form
= SQLFORM.factory(*[f for f in db.mytable if f.name in fields])

   
if form.accepts(request,session):
      session
.wizard.update(form.vars)
      redirect
(URL(args=step+1))
   
else:
      db
.mytable.insert(**session.wizard)
      session
.flash = T('wizard completed')
      redirect
(fields)
   
return dict(form=form,step=step)
 

The lines of code that I have problems with fully understanding are underlined in red above ! can someone please explain it to me in plain english !! what does that line does,  with the star ( * ) in front of the [...the for loop...], ?
thank you !

Knowing that I have 3 tables, i cannot use that code as is ! because the real table name "db.mytable" is used !! I have 3 different tables !
the fields are fields of the 3 tables ...

can I use the table_name attribute in this context ... ( like table_name = dummy_table ) while this attribute does not really exist in my db ... just for the session .. and later on ... when it is time to insert the fields into my real 3 tables, I  replace the following single line of code seen above  :

db.mytable.insert(**session.wizard)

and replacing it with 3 lines of code like :

db.mytable1.insert(**db.dummy_table._filter_fields(form.vars)
db.mytable2.insert(**db.dummy_table._filter_fields(form.vars)
db.mytable3.insert(**db.dummy_table._filter_fields(form.vars)


Can someone shed some light for me ... I have tried it ! .. and it does not work ! ... and I am thinking that it should ! ... am I wrong ??? ..

thank you for any assistance on this matter !

Don



Don_X

unread,
Aug 21, 2012, 12:55:10 AM8/21/12
to web...@googlegroups.com
How can I re-write the lines of code :

if isinstance(fields,tuple):
      form
= SQLFORM.factory(*[f for f in db.mytable if f.name in fields])


to take into account my 3 tables ??? ... that is my real problem !


Anthony

unread,
Aug 21, 2012, 1:21:41 AM8/21/12
to web...@googlegroups.com
*[f for f in db.mytable if f.name in fields]

The above is a list comprehension. It returns a list of field objects from the db.mytable table -- including only the fields whose names are found in "fields". The * in front of the list causes the .factory() method to treat each item in the list as a separate argument (rather than taking the entire list as a single argument) -- this is equivalent to manually entering each field as a separate argument to .factory().

With three tables, you could produce a similar list by looping over the tables and then the fields in the tables, or if you really like list comprehensions:

mytables = ['table1', 'table2', 'table3']
form_fields
= []
[form_fields.extend([db[t][f] for f in db[t].fields if f in fields]) for t in mytables]
form
= SQLFORM.factory(*form_fields)

Anthony

Don_X

unread,
Aug 21, 2012, 10:00:04 AM8/21/12
to
thank you Anthony for the explanation ..
I tried to do it that way, but it does not work .. what am I doing wrong ???

def testpage():
   STEPS
= {0: ('Iagreeto','first_name','last_name','email','password','sex','birth_date','usertype'), # fields for 1st table and first step
           
1: ('user_adrss','user_city','user_prov','user_postalcode','Country'),     # fields for 2nd table and 2nd step
           
2: ('language_spoken','Other_language','user_picture','user_description','user_story'),  # fields for the final table and 3rd step
           
3: URL('done')}

   
   step
= int(request.args(0) or 0)
   
if not step in STEPS: redirect(URL(args=0))
   fields
= STEPS[step]
   
if step==0:

      session
.testpage = {}
   
if isinstance(fields,tuple):
      mytables
= ['auth_user','user_location', 'user_profile']

      form_fields
= []
     
[form_fields.extend([db[t][f] for f in db[t].fields if f in fields]) for t in mytables]
      form
= SQLFORM.factory(*form_fields)

   
   if form.accepts(request,session):
         session
.testpage.update(form.vars)
         redirect
(URL(args=step+1))
   
else:
     
for k in mytables :
         db
[k].insert(**session.testpage)

      session
.flash = T('wizard completed')
      redirect
(fields)
   
return dict(form=form,step=step)

and it does not work .... what am I doing wrong ...
Message has been deleted

Don_X

unread,
Aug 21, 2012, 9:58:06 AM8/21/12
to web...@googlegroups.com
Finally ... Anthony,

Thank you Bro !

You are a real prince  !!! ... I got it to work in a wizard format with 3 steps & 3 tables !!  ...  My god ! this feels liberating !

My only problem now is with the image upload in the form ....  on the last step ... but that is a separate issue ! ...

I will try to work it out later !

thanks again !
;)

Carlos Zenteno

unread,
Nov 8, 2013, 12:36:30 PM11/8/13
to web...@googlegroups.com
Don, can you tell me how you made it work?
I am not having any luck making it work and Anthony's
answer has been deleted for some reason.

thanks...

Richard Vézina

unread,
Nov 8, 2013, 1:41:00 PM11/8/13
to web2py-users


--
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
---
You received this message because you are subscribed to the Google Groups "web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web2py+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Anthony

unread,
Nov 8, 2013, 2:03:37 PM11/8/13
to web...@googlegroups.com
That answer is still on Google Groups. The message that was deleted was another message from Don_X and didn't appear to contain anything relevant to the problem solution.

Anthony

Carlos Zenteno

unread,
Nov 12, 2013, 2:01:05 PM11/12/13
to web...@googlegroups.com
Thanks for the responses.

I am using the answer on Google Groups but somehow
it seemed that the missing message gave the solution
as why the code showed did not work.

It is not working for me too, so I will keep trying.
Thanks again...

Reply all
Reply to author
Forward
0 new messages