Quem nunca precisou fazer um form wizard com web2py?, não?, então se prepare pois algum dia vai precisar, e quando precisar talvez você passe pelos mesmos problemas que passei ou pior.

Felizmente eu sempre compartilho as soluções dos meus problemas pois certamente isso pode ajudar a muitos.

Para este exemplo, vamos supor que você queira fazer um cadastro com dois ou mais passos (form wizard), com 4 campos (irei aproveitar a tabela padrão “auth_user”), são eles: “username, email, first_name, last_name” sendo que no primeiro passo teremos os campos username e email e no segundo passo os campos first_name e last_name.

Controllers:

def step1():
    form=SQLFORM(db.auth_user,fields=['username','email'])
    if form.accepts(request.vars, dbio=False):
        session.step1=request.vars
        redirect('step2')
    return dict(form=form)
 
def step2():
    form=SQLFORM(db.auth_user,fields=['username','email','first_name','last_name'])    
    if request.post_vars:
        request.vars.update(session.step1)    
    if form.accepts(request.vars):
        session.flash=T("Dados gravados")
        return redirect('index')
    return dict(form=form)

Views:

Step1

{{extend 'layout.html'}}
 
<fieldset>
<legend>Passo 1</legend>
 
    {{=form.custom.begin}}
 
    <div>
        <label>Username</label>
        {{=form.custom.widget.username}}
    </div>
 
    <div>
        <label>Email</label>
        {{=form.custom.widget.email}}
    </div>
 
    <div>
    {{=form.custom.submit}}
    </div>
    {{=form.custom.end}}
 
</fieldset>

Step2

{{extend 'layout.html'}}
 
<fieldset>
<legend>Passo 2</legend>
 
    {{=form.custom.begin}}
 
    <div>
        <label>First name</label>
        {{=form.custom.widget.first_name}}
    </div>
 
    <div>
        <label>Last name</label>
        {{=form.custom.widget.last_name}}
    </div>
 
    <div>
    {{=form.custom.submit}}
    </div>
    {{=form.custom.end}}
 
</fieldset>

Realmente é bem simples, a mágica aqui é a seguinte:

- No step1, definimos apenas os fields=['username','email'] para o SQLFORM e dbio=False para o form.accepts, desta forma iremos exibir apenas os dois campos descritos em fields e quando o formulário for submetido, os dados não serão salvos pois o dbio está definido como False.

- Criei também uma variável de sessão session.step1 e atribui o request.vars para ela, é desta forma que os dados serão passados para o segundo método (step2) através do método redirect(‘step2′).

- Outro detalhe importante que no step2, definimos todos os fields=['username','email','first_name','last_name'], sendo que os dois primeiros, já estarão preenchidos pois o usuário fez isso no passo um. O mais importante aqui é não exibir estes campos na view.

- Como os dados submetidos pelo step1 estão na sessão, lembra?, iremos atualizar o request.vars com estes dados, mas somente quando o usuário submeter no step2, fizemos isso através do comando

if request.post_vars:
        request.vars.update(session.step1)

- E para finalizar, o comando form.accepts do step2 se encarrega de fazer toda a validação e também gravar os dados no banco, veja que não definimos o dbio e o padrão dele é True (gravar no db).

Espero que seja útil, até a próxima.