Workflow
The web2py workflow is the following:
- An HTTP requests arrives to the web server (the built-in Rocket server or a different server connected to web2py via WSGI or another adapter). The web server handles each request in its own thread, in parallel.
- The HTTP request header is parsed and passed to the dispatcher (explained later in this chapter in Dispatching section).
- The dispatcher decides which of the installed application will handle the request and maps the PATH_INFO in the URL into a function call. Each URL corresponds to one function call.
- Requests for files in the static folder are handled directly, and large files are automatically streamed to the client.
- Requests for anything but a static file are mapped into an action (i.e. a function in a controller file, in the requested application).
- Before calling the action, a few things happen: if the request header contains a session cookie for the app, the session object is retrieved; if not, a session id is created (but the session file is not saved until later); an execution environment for the request is created; models are executed in this environment.
- Finally the controller action is executed in the pre-built environment.
- If the action returns a string, this is returned to the client (or if the action returns a web2py HTML helper object, it is serialized and returned to the client).
- If the action returns an iterable, this is used to loop and stream the data to the client.
- If the action returns a dictionary, web2py tries to locate a view to render the dictionary. The view must have the same name as the action (unless specified otherwise) and the same extension as the requested page (defaults to .html); on failure, web2py may pick up a generic view (if available and if enabled). The view sees every variable defined in the models as well as those in the dictionary returned by the action, but does not see global variables defined in the controller.
- The entire user code is executed in a single database transaction unless specified otherwise.
- If the user code succeeds, the transaction is committed.
- If the user code fails, the traceback is stored in a ticket, and a ticket ID is issued to the client. Only the system administrator can search and read the tracebacks in tickets.
There are some caveats to keep in mind:
- Models in the same folder/subfolder are executed in alphabetical order.
- Any variable defined in a model will be visible to other models following alphabetically, to the controllers, and to the views.
Conditional models
- Models in subfolders are executed conditionally based on the controller in use. This avoids processing all table definitions at each request. For example, if the user has requested “/a/c/f” where “a” is the application, “c” is the controller, and “f” is the function (action), then the following models are executed:
applications/a/models/*.py
applications/a/models/c/*.py
applications/a/models/c/f/*.py
This behaviour is enforced by default. Altering the response.models_to_run
regex list, you can force the behaviour you want. Look at response for additional details.
- The requested controller is executed and the requested function is called. This means all top-level code in the controller is also executed at every request for that controller.
- The view is only called if the action returns a dictionary.
- If a view is not found, web2py tries to use a generic view. By default, generic views are disabled, although the ‘welcome’ app includes a line in /models/db.py to enable them on localhost only. They can be enabled per extension type and per action (using
response.generic_patterns
). In general, generic views are a development tool and typically should not be used in production. If you want some actions to use a generic view, list those actions inresponse.generic_patterns
(discussed in more detail in the chapter on Services).
The possible behaviors of an action are the following:
Return a string:
def index():
return 'data'
Return a dictionary for a view:
def index():
return dict(key='value')
the list of all local variables in the action may be a convenient dictionary to use:
def index():
return locals()
Redirect the user to another page:
def index():
redirect(URL('other_action'))
Return an HTTP status code other than “200 OK”:
def index():
raise HTTP(404)
Return a helper
for example a FORM:
def index():
return FORM(INPUT(_name='test'))
(this is mostly used for Ajax callbacks and components, see Chapter 12).
When an action returns a dictionary, it may contain code generated by helpers, including forms based on database tables or forms from a factory, for example:
def index():
return dict(form=SQLFORM.factory(Field('name')).process())
(all forms generated by web2py use postbacks, see Chapter 3).
Helpers are also useful for downloading and streaming. For example the “download” action, defined in the scaffolding application, uses the response.download
helper for downloading of uploaded files:
def download():
return response.download(request, db)
look at response for additional details.
The response.stream
helper method allows serving of arbitrary content:
def index():
return response.stream('/tmp/foo.bar', request=request, attachment=True)
look at response for additional details.