session
session
is another instance of the Storage
class. Whatever is stored into session
for example:
session.myvariable = "hello"
can be retrieved at a later time:
a = session.myvariable
as long as the code is executed within the same session by the same user (provided the user has not deleted session cookies and the session has not expired). Because session
is a Storage
object, trying to access an attribute/key that has not been set does not raise an exception; it returns None
instead.
The session object has three important methods. One is forget
:
session.forget(response)
It tells web2py not to save the session. This should be used in those controllers whose actions are called often and do not need to track user activity. session.forget()
prevents the session file from being written, regardless of whether it has been modified. session.forget(response)
additionally unlocks and closes the session file. You rarely need to call this method since sessions are not saved when they are not changed. However, if the page makes multiple simultaneous Ajax requests, it is a good idea for the actions called via Ajax to call session.forget(response)
(assuming the session is not needed by the action). Otherwise, each Ajax action will have to wait for the previous one to complete (and unlock the session file) before proceeding, which will slow down the page loading. Notice that sessions are not locked when stored in the database.
Another method is:
session.secure()
which tells web2py to set the session cookie to be a secure cookie. This should be set if the app is going over https. By setting the session cookie to be secure, the server is asking the browser not to send the session cookie back to the server unless over an https connection.
The other method is connect
. By default sessions are stored on the filesystem and a session cookie is used to store and retrieve the session.id
. Using the connect method it is possible to tell web2y to store sessions in the database or in the cookies thus eliminating need to access the filesystem for session management.
For example to store sessions in the database:
session.connect(request, response, db, masterapp=None)
where db
is the name of an open database connection (as returned by the DAL). It tells web2py that you want to store the sessions in the database and not on the filesystem. session.connect
must come after db=DAL(...)
, but before any other logic that requires session, for example, setting up Auth
.
web2py creates a table:
db.define_table('web2py_session',
Field('locked', 'boolean', default=False),
Field('client_ip'),
Field('created_datetime', 'datetime', default=now),
Field('modified_datetime', 'datetime'),
Field('unique_key'),
Field('session_data', 'text'))
and stores cPickled sessions in the session_data
field.
The option masterapp=None
, by default, tells web2py to try to retrieve an existing session for the application with name in request.application
, in the running application.
If you want two or more applications to share sessions, set masterapp
to the name of the master application.
To store sessions in cookies instead you can do:
session.connect(request, response, cookie_key='yoursecret', compression_level=None)
Here cookie_key
is a symmetric encryption key. compression_level
is an optional zlib
encryption level.
While sessions in cookie are often recommended for scalability reason they are limited in size. Large sessions will result in broken cookies.
You can check the state of your application at any time by printing the request
, session
and response
system variables. One way to do it is to create a dedicated action:
def status():
return dict(request=request, session=session, response=response)
In the “generic.html” view this is done using {{=response.toolbar()}}
.
Don’t store user-defined classes in session
Variables stored in the session are preserved between requests by serialisation.
Sessions are retrieved before an execution environment for the request is created, that is before any model and controller is executed, when user classes are not yet defined. Therefore user defined classes cannot be pickled.
Classes defined in modules are also a grey area and they should not put in storage. Most of the time they work but they can break. This is because, for example, if you restart the web server and a user retrieves a session, this may happen before the module is imported. Same problem when the web server starts a new worker process. Same problem in a distributed environment.
Separate sessions
If you are storing sessions on the filesystem and you have lots of them, the file system access may become a bottle-neck. One solution is the following:
session.connect(request, response, separate=True)
By setting separate=True
web2py will store sessions not in the “sessions/“ folder but in subfolders of the “sessions/“ folder. The subfolder will be created automatically. Sessions with the same prefix will be in the same subfolder. Again, note that the above must be called before any logic that might require the session.