I can get stuff done using web2py, but sometimes I have a little trouble understanding exactly when controller code is called in certain cases. For self-submitting forms, I'm not sure I quite get it.
My current understanding is that the controller function is called twice. Once for generating the dict, that is passed to the html template language and then once more when the form is submitted to e.g. store the values from the form in the db and then redirect to another page/controller function. It seems customary to control the flow using form.accepts - the first time the function is call, the .accepts method fails and the flow continues to the return dict, to render the page and the second time to set db values and redirect before the return. Am I spot on or way off? If I'm correct here, I still have the following questions: 1) Isn't all code before the form.accepts executed two times? 2) How does the form know that the same page should be reloaded - is there an implicit form action that is set to this by default? 3) What happens if form.accept fails its validators on submitting - doesn't the flow of code cause the same page to be rendered again? The first question is important in a rather complex controller function I'm messing with - copied below. As you can see, there's a lot going on before the form.accepts. Any comments on simplification or optimization is greatly appreciated. I'm both a web and Python n00b, so please don't ridicule me too much ;-) ---- controller code below def index(): rows=db().select(db.frequencies.id, db.frequencies.Channel, db.frequencies.Frequency, db.frequencies.Bandwidth, db.frequencies.UsedFor, orderby=db.frequencies.Frequency) source_selects = {} for row in rows: usedDynamic=db(((db.frequencies.UsedFor==db.sources.id) & (db.sources.isDynamic==True))).select(db.sources.id) unusedDynamic=db((~db.sources.id.belongs(usedDynamic)) & (db.sources.isDynamic==True)).select(db.sources.id) unusedFreeAndThis=db((db.sources.id==1) | (db.sources.id.belongs(unusedDynamic)) | (row.UsedFor==db.sources.id)).select(db.sources.id) source_options = [OPTION(s.Name,_value=s.id) for s in db((db.sources.id.belongs(unusedFreeAndThis))).select(db.sources.ALL)] selectedItem=db((db.frequencies.UsedFor==db.sources.id) & (row.id==db.frequencies.id)).select(db.sources.id, db.sources.isDynamic, db.sources.Name)[0] if selectedItem.isDynamic: selected=selectedItem.id source_selects[row.id] = SELECT(*source_options,**dict(_name=row.id,requires=IS_IN_DB(db,'sources.id'),value=selected)) source_selects[row.id]['_onchange']="this.form.submit();" else: source_selects[row.id] = TD(B(selectedItem.Name)) form=FORM(TABLE(THEAD(TR(TD('Channel'),TD('Centre Frequency'), TD('Bandwidth'), TD('Used for'))), *[TR(row.Channel, row.Frequency, row.Bandwidth, source_selects[row.id]) for row in rows])) if form.accepts(request.vars, session): for v in form.vars: db(db.frequencies.id == v).update(UsedFor=form.vars[v]) redirect(URL(r=request, f='index')) return dict(form=form) ------ db code db.define_table('sources', Field('Name','string'), Field('isDynamic','boolean') ) db.define_table('frequencies', Field('Channel','string'), Field('Frequency','integer'), Field('Bandwidth','integer'), Field('UsedFor', db.sources) )