How to use formkey with forms defined in the view?

707 views
Skip to first unread message

Yarin

unread,
Aug 7, 2012, 10:11:18 AM8/7/12
to web...@googlegroups.com
Sometimes I need to define my forms in the view, but still want to use as much of web2py's form functionality as possible. In those cases I generally define the form in the controller as well, with corresponding fields, and then build a form in the view with the same formname.

This works, except that I can't figure out how to make use of formkey to prevent double posting in this scenario?

Controller:

def index():
 
    my_form
= FORM(INPUT(_name='name'))
 
        if my_form.accepts(request.vars,formname='my_form'):
 
        logger
.debug(my_form.vars.name)
 
        import time
        time
.sleep(1) # Wait a little to allow a double submission
 
        response
.flash = "Form accepted."
 
    elif my_form.errors:
        response
.flash = str(my_form.errors)
    else:
        pass
 
    return dict()


View:

{{extend 'layout.html'}}

<form method="POST">
   
<input type="text" name="name">
   
<input type="submit" value="Double Submit Me">
    <input type="hidden" name="_formname" value="my_form">
</form>

Anthony

unread,
Aug 7, 2012, 4:35:56 PM8/7/12
to
After calling form.accepts (or form.process), the generated formkey is stored in form.formkey. You can also use form.hidden_fields() to generate the _formname and _formkey hidden fields instead of creating them manually.

def index():
   
return dict(form=FORM(INPUT(_name='name')).process(formname='my_form'))

View:

<form method="POST">
   
<input type="text" name="name">
   
<input type="submit" value="Double Submit Me">
   
<input type="hidden" name="_formname" value="my_form">
    <input type="hidden" name="_formkey" value="{{=form.formkey}}">
</form>

or

<form method="POST">
   
<input type="text" name="name">
   
<input type="submit" value="Double Submit Me">
    {{=form.hidden_fields()}}
</form>

Anthony
Message has been deleted

Yarin

unread,
Aug 7, 2012, 3:55:36 PM8/7/12
to

OK- figured this out. Anthony's answer worked, but only after I added session to the .accepts(...) args // and or used form.process(...).accepted instead.

Working code below:

Controller:

def index():

 
    form
= FORM(INPUT(_name='name'))

 
   
if form.accepts(request.vars, session=session, formname='my_form'):
   
# OR if form.process(formname='my_form').accepted:

        logger
.debug(form.vars.name)


       
import time
        time
.sleep(1) # Wait a little to allow a double submission
        response
.flash = "Form accepted."

 
   
elif form.errors:
        response
.flash = str(form.errors)
   
else:
       
pass
 
   
return dict(form=form)



View:

<form method="POST">
   
<input type="text" name="name">
   
<input type="submit" value="Double Submit Me">

    {{=form.hidden_fields()}}
</form>



On Tuesday, August 7, 2012 11:34:12 AM UTC-4, Anthony wrote:
After calling form.accepts (or form.process), the generated formkey is stored in form.formkey. You can also use form.hidden_fields() to generate the _formname and _formkey hidden fields instead of creating them manually.

def index():
   
return dict(form=FORM(INPUT(_name='name')).process(formname='my_form'))

View:

<form method="POST">
   
<input type="text" name="name">
   
<input type="submit" value="Double Submit Me">
   
<input type="hidden" name="_formname" value="my_form">

   
<input type="hidden" name="_formkey" value="{{=form.formkey}}">
</form>

or

<form method="POST">
   
<input type="text" name="name">
   
<input type="submit" value="Double Submit Me">

    {{=form.hidden_fields()}}
</form>

Anthony

On Tuesday, August 7, 2012 10:11:18 AM UTC-4, Yarin wrote:

Anthony

unread,
Aug 7, 2012, 2:47:57 PM8/7/12
to web...@googlegroups.com
OK- figured this out, mostly. Anthony's answer worked, but only after I added session to the .accepts(...) args // and or used form.process(...).accepted instead.

Yes, the formkey is stored in the session, so you have to pass the session to form.accepts() for the formkey to be created. form.process() ultimately calls form.accepts(), and it automatically passes the session (unless you explicitly set session=None).
 
Note however that using {{=form.hidden_fields()}} in the view does NOT work for me (the form never gets accepted) even though the generated HTML looks fine. I don't have an explanation for this-

I tried your exact code, and {{=form.hidden_fields()}} seems to work fine for me.

Side note: In your code, you are processing the form twice -- once with form.accepts(), and a second time with form.process() in the returned dict.

Anthony

Yarin

unread,
Aug 7, 2012, 3:56:58 PM8/7/12
to web...@googlegroups.com
Anthony- you're right on both counts- sloppy copy and pasting on my part- edited my previous post, everything works. Thanks!-
Reply all
Reply to author
Forward
0 new messages