assuming form=SQLFORM(db.table,record_id)

 
form.accepts(request.vars,session,formname='xxx',hideerror=False,dbio=True)

does the following
1) if not request.vars._formname=='xxx' then form is not being self
submitted, generate a CSRF-prevention security key and store it in
session, return False
2) if not request.vars._formkey==CSRF-key-in-session, this is a double
form submission or a a CSRF attack, return False
3) use the depth first tree traversal algorithm to find all the INPUT,
SELECT and TEXTAREA objects in the form, check if they have a
corresponding entry in request.vars and validate it accordingly. If it
does not pass validation store the error in form.errors[fieldname] and
modify the form by injecting error messages in it (unless
hideerror=True). When validating each INPUT object, all validators are
executed in order, if one passes, it filters request.vars.fieldname
into form.vars.fieldname
4) for SQFORMS if dbio==True (default) and there are no form.errors it
does a db.table.insert(**form.vars) or
db(db.table.id==record_id).update(**form.vars) depending on whether
this is a create for or an update form (determined by the presence of
the record_id in form definition). If this is a create form, the id
returned by insert is stored in form.vars.id
5) If here and no errors return True

This is a nutshell. It is a bit more complicated because it needs to
deal with the odd behavior of select and checkboxes vs text input,
repeated fields names, the presence of Widgets which may override the
field validators and the way errors are to be displayed.

SQLFORM.accepts calls FORM.accepts (very similar to each other) are
the most complex piece of code in web2py. Not the one I am most happy
with. If I were to re-do it I would redo it differently (in particular
because of how widgets are dealt with) but the API is clean and it
works well.

Massimo

On Sep 16, 12:08 pm, Michael Ellis <michael.f.el...@gmail.com> wrote:
> Thanks, Jonathan.  That's approximately what I had reasoned it must be
> doing, but couldn't state as clearly as you have.
>
> So, if I'm now understanding it correctly, form.accepts() is roughly
> equivalent to the following conditions:
>
> (request contains submitted form elements) and
> (form key matches) and
> (all elements pass validation)
>
> The 'magic' is simply that clicking the submit button sends a second request
> to the controller that created it. So the form object only *seems* to
> persist;  in actuality, it's recreated from scratch when the second request
> comes in.
>
> All of which explains why I was unable to store extra info in the form
> object at view time and have it available after form.accepts() came back
> True.
>
> Is that a fair summary of how it works?
>
> On Thu, Sep 16, 2010 at 11:04 AM, Jonathan Lundell <jlund...@pobox.com>wrote:
>
> > On Sep 16, 2010, at 7:26 AM, Michael Ellis wrote:
>
> > > I was never much bothered by either of those issues, but there is one
> > > bit of 'magic' that did (and to some extent still does) confuse me.
> > > I'm wondering if it might be worthwhile to give an detailed
> > > explanation what goes on in form.accepts().
>
> > > When I first saw the idiom
>
> > >   if form.accepts():
> > >      ...
> > >   return dict(form=form)
>
> > > my assumption was that the call to form.accepts() was somehow
> > > rendering and transmitting the page and waiting for a user response.
> > > But then, I wondered how that could be since the form isn't passed to
> > > the view until the return() is executed.  Then I tried tracing a
> > > controller and saw that it was being called multiple times.  I got
> > > lost down in the gluon code and more or less gave up trying to find
> > > out exactly how the rabbit gets into the hat. Now I just use it and
> > > trust that it works, but it still bothers me not to know what's going
> > > on under the hood.
>
> > I've had the same reaction. The key to my understanding form.accepts, fwiw,
> > was reading accepts itself. Keep in mind that web2py encourages form
> > self-submission. That implies that the same code (controller/function)
> > typically needs to run twice: once to create the page+form for display, and
> > again to handle the form's submission.
>
> > So form.accepts() is telling you whether it's the first time through, form
> > creation (False) or the second, form submission (True). It's a little more
> > complicated than that because of validation and error handling, but that's
> > it in a nutshell.
>
>

Reply via email to