stop form from reposting with refresh

1,289 views
Skip to first unread message

Audra Rudys

unread,
Sep 28, 2010, 12:31:27 AM9/28/10
to web...@googlegroups.com
Hi all,
I'm new to web2py and just dipping my toe in with a simple posting form (2 fields, a summary and description, displays form and the previously submitted values below -- date posted, summary, description.)  I notice that after posting, my summary and description are cleared out in the form, however, if I refresh the page, the last post I had gets reposted, resulting in duplicates.  I have a validator on summary and description so if they're blank, it doesn't allow the user to post with the submit button, but this doesn't kick in with refresh.  Is there a trick for stopping this, wouldn't want these duplicates in a live application database.

By the way, kudos to all the developers/folks working on web2py, what a great framework!  Can't wait to use more of its functionality!

Thanks,
Audra

mdipierro

unread,
Sep 28, 2010, 12:52:16 AM9/28/10
to web2py-users
When you say "refresh the page" you mean you "click the reload
button". That causes a form re-submission.

To prevent it, redirect(URL()) after form.accepts(...)

David Ripplinger

unread,
Apr 20, 2013, 8:50:30 AM4/20/13
to web...@googlegroups.com
How do I make it so that the form does not resubmit upon clicking the browser reload button even when the form has errors, but still display the errors? I just hate form resubmissions popping up ever. Nobody ever uses that "feature" of browsers intentionally.

Niphlod

unread,
Apr 20, 2013, 8:58:10 AM4/20/13
to web...@googlegroups.com
you can't forge the browser standard behaviour..... if the page is the result of a POST, hitting "refresh" will always re-issue a POST.

David Ripplinger

unread,
Apr 20, 2013, 8:58:54 AM4/20/13
to web...@googlegroups.com
Furthermore, since I am using custom checks on the validity of data (i.e. I'm doing checks that go way beyond putting a "requires" object in a Field object), I am currently creating a custom FORM object, and then after form.accepts passes, I check if adding in the data raises exceptions. If an exception is raised, it is caught and I add the message of the exception to form.errors['field'].

The problem with me breaking the typical usage this way is that subsequent form submissions that are valid do get accepted and processed, but the errors from previous invalid submissions still display. I can go set form.errors = {}, I suppose, for every form on my page, but this could become tedious. Is there a better way?

Anthony

unread,
Apr 20, 2013, 10:09:46 AM4/20/13
to web...@googlegroups.com
It's not quite clear what you're doing -- perhaps you can show a code example. Do you get a lot of users reloading post-submission pages and ignoring the browser warning about re-submitting the form?

Anthony

David Ripplinger

unread,
Apr 20, 2013, 10:29:24 AM4/20/13
to web...@googlegroups.com
Here is an example form created and handled in the controller's index() function:

addCategoryForm = FORM('Add category:',
        INPUT(_name='category', requires=IS_NOT_EMPTY()),
        INPUT(_type='submit'))
    if addCategoryForm.accepts(request, session, formname='addCategory'):
        try:
            create_category(request.vars.category, auth.user.budget_id, auth.user.id)
            redirect(URL())
        except Exception, e:
            addCategoryForm.errors['category'] = e.message

I don't like using the SQLFORM object because the category table contains a budget_id, a kind (since I have more than one type of category), and an isActive boolean, all of which are either set to a default value or depend on the user that is logged in. The db function create_category() verifies that the user has permission to edit that budget (no, auth_groups don't work for me in this case), and it performs validation on the name by checking for unwanted characters and making sure that the name is unique for that specific combination of kind and budget_id. Thus the typical 'requires=unique' or whatever it is when defining a table is insufficient.

This means that addCategoryForm.accepts() only does part of the validation. If it passes the create_category() function without error, then it is truly successful and I can redirect the url to avoid the stupid resubmission of a post that results from a page refresh. I would like to be able to also avoid the post resubmission after an invalid post. I could put a redirect(URL()) in the code no matter what, but then the error messages get erased.

My problem stated in my last post to this topic, that of having the error messages not go away, turned out to be because of something else I was doing wrong, which is now fixed, so that is actually not related much.

Anthony

unread,
Apr 20, 2013, 2:46:57 PM4/20/13
to web...@googlegroups.com

addCategoryForm = FORM('Add category:',
        INPUT(_name='category', requires=IS_NOT_EMPTY()),
        INPUT(_type='submit'))
    if addCategoryForm.accepts(request, session, formname='addCategory'):
        try:
            create_category(request.vars.category, auth.user.budget_id, auth.user.id)
            redirect(URL())
        except Exception, e:
            addCategoryForm.errors['category'] = e.message

I don't like using the SQLFORM object because the category table contains a budget_id, a kind (since I have more than one type of category), and an isActive boolean, all of which are either set to a default value or depend on the user that is logged in.

For any fields you don't want displayed, just set the readable and writable attributes to False. You can also specify the "fields" argument to SQLFORM to tell it exactly which fields to include.
 
The db function create_category() verifies that the user has permission to edit that budget (no, auth_groups don't work for me in this case)

This can be checked either via an onvalidation function or prior to even creating/processing the form.
 
, and it performs validation on the name by checking for unwanted characters and making sure that the name is unique for that specific combination of kind and budget_id. Thus the typical 'requires=unique' or whatever it is when defining a table is insufficient.

This can be done either with an onvalidation function or with two validators:

    requires = [IS_MATCH(...), IS_NOT_IN_DB(db([set filtered based on kind and budget_id]), ...)]
 
This means that addCategoryForm.accepts() only does part of the validation.

This is not necessary. You are giving up all the automatic processing just to do some custom validation that you can already do with existing validation functionality.

Finally, why is create_category in a try..except? Can't you just have it return an error message rather than raise an exception (if you do raise an exception, it should be a specific one, so you don't mistakenly catch real errors in the code).

Anthony
Reply all
Reply to author
Forward
0 new messages