Commit 1a8bdfb5 authored by matt@zope.com's avatar matt@zope.com

Update session docs; merge two into one (elimininating separate

session-admin doc)
parent 218f54f6
Session Tracking
Session Administration
Overview
......@@ -25,23 +25,197 @@ Session Tracking
To facilitate sessions on systems without ZEO, you may wish to create
a *Temporary Folder* to store your Transient Objects.
Usage
The session data manager will begin automatically adding a SESSION
object to the REQUEST in the default configuration.
The simplest way to use sessions is to activate the "Automatic Session"
feature in the Session Data Manager object. This will cause a session
object to be fetched or created if necessary and stored in the 'REQUEST'
object under the name 'SESSION'.
Session Data Object Expiration
This 'SESSION' object behaves as a dictionary, so the following python
script would demonstrate incrementing a counter in the session::
Session data objects expire after the period between their last
access and "now" exceeds the timeout value provided to the
transient object container which hold them. No special action need
be taken to expire session data objects.![1]
request = context.REQUEST
session = request.SESSION
![1] See "Session Data Object Expiration Considerations" in the
Concepts and Caveats section below for details on session data
expiration.
counter = session.get('counter',0) + 1
session['counter'] = counter
Importing And Exporting Session Data Objects
For more advanced programming details, see the *Session API* documentation.
In some circumstances, it is useful to be able to "export" all
the session data from a specific transient object container in order
to "import" it to another. This may be necessary when migrating
data between containers or when upgrading the session tracking
implementation to a more recent version.
You can export data from a transient object container by visiting
its "Advanced" tab, and choosing "Export Session Data". A file
will be written to the hard disk of the Zope server you're
talking to in the 'var' directory of the Zope instance named
"sessiondata.zexp".
To import exported session data, choose "Import Session Data"
from the Advanced tab of the transient object container you're
migrating to. The "sessiondata.zexp" file containing the
exported session data will be read from disk and placed into the
transient object container.
The contents of RAM-based (internal) transient object containers
cannot be exported, and you may not import session data into an
internal transient object container.
Concepts and Caveats
Session Id (Non-)Expiration
Unlike many other sessioning implementations, core session
tracking session tokens (ids) do not actually themselves expire.
They persist for as long as their conveyance mechanism allows.
For example, a session token will last for as long as the session
token cookie persists on the client, or for as long as someone
uses a bookmarked URL with a session token in it. The same id
will be obtained by a browser id manager on every visit by that
client to a site - potentially indefinitely depending on which
conveyance mechanisms you use and your configuration for cookie
persistence. It may be useful to think of a Zope browser id as
a "browser id" for this reason.
In lieu of exipry of browser ids, the transient object container
which holds session data objects implements a policy for data
object expiration. If asked for a session data object related
to a particular browser id which has been expired by a transient
object container, a session data manager will a return a new
session data object.
Session Data Object Expiration Considerations
Because Zope has no scheduling facility, the sessioning
machinery depends on the continual exercising of itself to
expire session data objects. If the sessioning machinery is not
exercised continually, it's possible that session data
objects will stick around longer than the time specified by
their transient object container timeout value. For example:
- User A exercises application machinery that generates a
session data object. It is inserted into a transient object
container which advertises a 20-minute timeout.
- User A "leaves" the site.
- 40 minutes go by with no visitors to the site.
- User B visits 60 minutes after User A first generated his
session data object, and exercises app code which hands out
session data objects. *User A's session is expired at this
point, 40 minutes "late".*
Sessioning and Transactions
The existing transient object container implementations interact
with Zope's transaction system. If a transaction is aborted,
the changes made to session data objects during the transaction
will be rolled back.
Acquisition-Wrapped Objects
The sessioning machinery unwraps acquisition-wrapped objects
before storing them during a session_data_object.set or
session_data_object.__setitem__ operation. Practically, this
means you can safely pass acquisition-wrapped objects in to the
sessioning machinery (for example, a DTML Document obtained via
traversal) as values within a session data object. The stored
reference will be to the bare unwrapped object. (new in 0.9)
Mutable Data Stored Within Session Data Objects
If you mutate an object stored as a value within a session data
object, you'll need to notify the sessioning machinery that the
object has changed by calling 'set' or '__setitem__' on the
session data object with the new object value. For example::
session = self.session_data_manager.getSessionData()
foo = {}
foo['before'] = 1
session.set('foo', foo)
# mutate the dictionary
foo['after'] = 1
# performing session.get('foo') 10 minutes from now will likely
# return a dict with only 'before' within!
You'll need to treat mutable objects immutably, instead. Here's
an example that makes the intent of the last example work by
doing so::
session = self.session_data_manager.getSessionData()
foo = {}
foo['before'] = 1
session.set('foo', foo)
# mutate the dictionary
foo['after'] = 1
# tickle the persistence machinery
session.set('foo', foo)
An easy-to-remember rule for manipulating data objects in
session storage: always explicitly place an object back into
session storage whenever you change it. For further reference,
see the "Persistent Components" chapter of the Zope Developer's
Guide at http://www.zope.org/Documentation/ZDG.
Session Data Object Keys
A session data object has essentially the same restrictions as a
Python dictionary. Keys within a session data object must be
hashable (strings, tuples, and other immutable basic Python
types; or instances which have a __hash__ method). This is a
requirement of all Python objects that are to be used as keys to
a dictionary. For more information, see the associated Python
documentation at
http://www.python.org/doc/current/ref/types.html (Mappings ->
Dictionaries).
In-Memory Session Data Container RAM Utilization
Each session data object which is added to an "internal"
(RAM-based) transient object container will consume at least 2K of
RAM.
Mounted Database-Based Session Data Container/Internal Session
Data Container Caveats
Persistent objects which have references to other persistent
objects in the same database cannot be committed into a mounted
database because the ZODB does not currently handle
cross-database references.
"Internal" (RAM-based) transient object containers are currently
implemented as objects within (automatically) mounted ZODB
databases. For this reason, they are equivalent in operation to
external transient object containers which are placed in a manually
mounted database.
If you use an internal transient object container or an external
transient object container that is accessed via a "mounted"
database, you cannot store persistent object instances which
have already been stored in the "main" database as keys or
values in a session data object. If you try to do so, it is
likely that an 'InvalidObjectReference' exception will be raised
by the ZODB when the transaction involving the object attempts
to commit. As a result, the transaction will fail and the
session data object (and other objects touched in the same
transaction) will fail to be committed to storage.
If your "main" ZODB database is backed by a nonundoing storage,
you can avoid this condition by storing session data objects in
an external data container instantiated within the "main" ZODB
database. If this is not an option, you should ensure that
objects you store as values or keys in a session data object
held in a mounted transient object container are instantiated "from
scratch" (via their constructors), as opposed to being "pulled
out" of the main ZODB.
Networking with ZEO
......@@ -52,6 +226,62 @@ Session Tracking
thus any session data stored in a Temporary Folder will not be
distributed to other ZEO clients.
Conflict Errors
This session tracking software stores all session state in
Zope's ZODB. The ZODB uses an optimistic concurrency strategy
to maintain transactional integrity for simultaneous writes.
This means that if two objects in the ZODB are changed at the
same time by two different connections (site visitors) that a
"ConflictError" will be raised. Zope retries requests that
raise a ConflictError at most 3 times. If your site is
extremely busy, you may notice ConflictErrors in the Zope debug
log (or they may be printed to the console from which you run
Zope). An example of one of these errors is as follows::
2001-01-16T04:26:58 INFO(0) Z2 CONFLICT Competing writes at, /getData
Traceback (innermost last):
File /zope/lib/python/ZPublisher/Publish.py, line 175, in publish
File /zope/lib/python/Zope/__init__.py, line 235, in commit
File /zope/lib/python/ZODB/Transaction.py, line 251, in commit
File /zope/lib/python/ZODB/Connection.py, line 268, in commit
ConflictError: '\000\000\000\000\000\000\002/'
Errors like this in your debug log (or console if you've not
redirected debug logging to a file) are normal to an extent. If
your site is undergoing heavy load, you can expect to see a
ConflictError perhaps every 20 to 30 seconds. The requests
which experience conflict errors will be retried automatically
by Zope, and the end user should *never* see one. Generally,
session data objects attempt to provide application-level
conflict resolution to reduce the limitations imposed by
conflict errors NOTE: to take advantage of this feature, you
must be running Zope 2.3.1 or better, and you must be using it
with a storage such as FileStorage or SessionStorage which
supports application-level conflict resolution.
Zope Versions and Sessioning
Zope Versions are not particularly useful in combination with
sessioning. Particularly, if you change the properties of a
session data manager or browser id manager while working in a
Version on a "production" site, it may cause the sessioning
machinery to stop working for unversioned visitors to the site
due to the "locking" nature of versions. To work around this
problem, do not lock any sessioning-related objects while in a
Version. Alternately, do not use Versions.
Extending The Session Tracking Product
Implementing Alternate Session Data Managers and Data Containers
Alternate session data managers and data containers (perhaps
using a SQL database as a persistence mechanism) may be
implemented if they adhere to the interfaces outlined in the
SessioningInterfaces.py documentation which ships with this
software.
See Also
- "Transient Objects":../../Transience/Help/Transience.stx
......@@ -61,5 +291,3 @@ Session Tracking
- "Session API":SessionInterfaces.py
- "Session API Programming":sessionapi-prog.stx
- "Session Administration":session-admin.stx
......@@ -104,5 +104,3 @@ See Also
- "Session Tracking":Sessions.stx
- "Session Administration":session-admin.stx
......@@ -57,4 +57,3 @@ See Also
- "Session Tracking":Sessions.stx
- "Session Administration":session-admin.stx
......@@ -41,4 +41,3 @@ See Also
- "Session Tracking":Sessions.stx
- "Session Administration":session-admin.stx
Session Administration
Session Data Object Expiration
Session data objects expire after the period between their last
access and "now" exceeds the timeout value provided to the
transient object container which hold them. No special action need
be taken to expire session data objects.![1]
![1] See "Session Data Object Expiration Considerations" in the
Concepts and Caveats section below for details on session data
expiration.
Importing And Exporting Session Data Objects
In some circumstances, it is useful to be able to "export" all
the session data from a specific transient object container in order
to "import" it to another. This may be necessary when migrating
data between containers or when upgrading the session tracking
implementation to a more recent version.
You can export data from a transient object container by visiting
its "Advanced" tab, and choosing "Export Session Data". A file
will be written to the hard disk of the Zope server you're
talking to in the 'var' directory of the Zope instance named
"sessiondata.zexp".
To import exported session data, choose "Import Session Data"
from the Advanced tab of the transient object container you're
migrating to. The "sessiondata.zexp" file containing the
exported session data will be read from disk and placed into the
transient object container.
The contents of RAM-based (internal) transient object containers
cannot be exported, and you may not import session data into an
internal transient object container.
Concepts and Caveats
Session Id (Non-)Expiration
Unlike many other sessioning implementations, core session
tracking session tokens (ids) do not actually themselves expire.
They persist for as long as their conveyance mechanism allows.
For example, a session token will last for as long as the session
token cookie persists on the client, or for as long as someone
uses a bookmarked URL with a session token in it. The same id
will be obtained by a browser id manager on every visit by that
client to a site - potentially indefinitely depending on which
conveyance mechanisms you use and your configuration for cookie
persistence. It may be useful to think of a Zope browser id as
a "browser id" for this reason.
In lieu of exipry of browser ids, the transient object container
which holds session data objects implements a policy for data
object expiration. If asked for a session data object related
to a particular browser id which has been expired by a transient
object container, a session data manager will a return a new
session data object.
Session Data Object Expiration Considerations
Because Zope has no scheduling facility, the sessioning
machinery depends on the continual exercising of itself to
expire session data objects. If the sessioning machinery is not
exercised continually, it's possible that session data
objects will stick around longer than the time specified by
their transient object container timeout value. For example:
- User A exercises application machinery that generates a
session data object. It is inserted into a transient object
container which advertises a 20-minute timeout.
- User A "leaves" the site.
- 40 minutes go by with no visitors to the site.
- User B visits 60 minutes after User A first generated his
session data object, and exercises app code which hands out
session data objects. *User A's session is expired at this
point, 40 minutes "late".*
Sessioning and Transactions
The existing transient object container implementations interact
with Zope's transaction system. If a transaction is aborted,
the changes made to session data objects during the transaction
will be rolled back.
Acquisition-Wrapped Objects
The sessioning machinery unwraps acquisition-wrapped objects
before storing them during a session_data_object.set or
session_data_object.__setitem__ operation. Practically, this
means you can safely pass acquisition-wrapped objects in to the
sessioning machinery (for example, a DTML Document obtained via
traversal) as values within a session data object. The stored
reference will be to the bare unwrapped object. (new in 0.9)
Mutable Data Stored Within Session Data Objects
If you mutate an object stored as a value within a session data
object, you'll need to notify the sessioning machinery that the
object has changed by calling 'set' or '__setitem__' on the
session data object with the new object value. For example::
session = self.session_data_mgr.getSessionData()
foo = {}
foo['before'] = 1
session.set('foo', foo)
# mutate the dictionary
foo['after'] = 1
# performing session.get('foo') 10 minutes from now will likely
# return a dict with only 'before' within!
You'll need to treat mutable objects immutably, instead. Here's
an example that makes the intent of the last example work by
doing so::
session = self.session_data_mgr.getSessionData()
foo = {}
foo['before'] = 1
session.set('foo', foo)
# mutate the dictionary
foo['after'] = 1
# tickle the persistence machinery
session.set('foo', foo)
An easy-to-remember rule for manipulating data objects in
session storage: always explicitly place an object back into
session storage whenever you change it. For further reference,
see the "Persistent Components" chapter of the Zope Developer's
Guide at http://www.zope.org/Documentation/ZDG.
Session Data Object Keys
A session data object has essentially the same restrictions as a
Python dictionary. Keys within a session data object must be
hashable (strings, tuples, and other immutable basic Python
types; or instances which have a __hash__ method). This is a
requirement of all Python objects that are to be used as keys to
a dictionary. For more information, see the associated Python
documentation at
http://www.python.org/doc/current/ref/types.html (Mappings ->
Dictionaries).
In-Memory Session Data Container RAM Utilization
Each session data object which is added to an "internal"
(RAM-based) transient object container will consume at least 2K of
RAM.
Mounted Database-Based Session Data Container/Internal Session
Data Container Caveats
Persistent objects which have references to other persistent
objects in the same database cannot be committed into a mounted
database because the ZODB does not currently handle
cross-database references.
"Internal" (RAM-based) transient object containers are currently
implemented as objects within (automatically) mounted ZODB
databases. For this reason, they are equivalent in operation to
external transient object containers which are placed in a manually
mounted database.
If you use an internal transient object container or an external
transient object container that is accessed via a "mounted"
database, you cannot store persistent object instances which
have already been stored in the "main" database as keys or
values in a session data object. If you try to do so, it is
likely that an 'InvalidObjectReference' exception will be raised
by the ZODB when the transaction involving the object attempts
to commit. As a result, the transaction will fail and the
session data object (and other objects touched in the same
transaction) will fail to be committed to storage.
If your "main" ZODB database is backed by a nonundoing storage,
you can avoid this condition by storing session data objects in
an external data container instantiated within the "main" ZODB
database. If this is not an option, you should ensure that
objects you store as values or keys in a session data object
held in a mounted transient object container are instantiated "from
scratch" (via their constructors), as opposed to being "pulled
out" of the main ZODB.
Conflict Errors
This session tracking software stores all session state in
Zope's ZODB. The ZODB uses an optimistic concurrency strategy
to maintain transactional integrity for simultaneous writes.
This means that if two objects in the ZODB are changed at the
same time by two different connections (site visitors) that a
"ConflictError" will be raised. Zope retries requests that
raise a ConflictError at most 3 times. If your site is
extremely busy, you may notice ConflictErrors in the Zope debug
log (or they may be printed to the console from which you run
Zope). An example of one of these errors is as follows::
2001-01-16T04:26:58 INFO(0) Z2 CONFLICT Competing writes at, /getData
Traceback (innermost last):
File /zope/lib/python/ZPublisher/Publish.py, line 175, in publish
File /zope/lib/python/Zope/__init__.py, line 235, in commit
File /zope/lib/python/ZODB/Transaction.py, line 251, in commit
File /zope/lib/python/ZODB/Connection.py, line 268, in commit
ConflictError: '\000\000\000\000\000\000\002/'
Errors like this in your debug log (or console if you've not
redirected debug logging to a file) are normal to an extent. If
your site is undergoing heavy load, you can expect to see a
ConflictError perhaps every 20 to 30 seconds. The requests
which experience conflict errors will be retried automatically
by Zope, and the end user should *never* see one. Generally,
session data objects attempt to provide application-level
conflict resolution to reduce the limitations imposed by
conflict errors NOTE: to take advantage of this feature, you
must be running Zope 2.3.1 or better, and you must be using it
with a storage such as FileStorage or SessionStorage which
supports application-level conflict resolution.
Zope Versions and Sessioning
Zope Versions are not particularly useful in combination with
sessioning. Particularly, if you change the properties of a
session data manager or browser id manager while working in a
Version on a "production" site, it may cause the sessioning
machinery to stop working for unversioned visitors to the site
due to the "locking" nature of versions. To work around this
problem, do not lock any sessioning-related objects while in a
Version. Alternately, do not use Versions.
Extending The Session Tracking Product
Implementing Alternate Session Data Managers and Data Containers
Alternate session data managers and data containers (perhaps
using a SQL database as a persistence mechanism) may be
implemented if they adhere to the interfaces outlined in the
SessioningInterfaces.py documentation which ships with this
software.
See Also
- "Session Administration":session-admin.stx
......@@ -20,4 +20,3 @@ See Also
- "Session Tracking":Sessions.stx
- "Session Administration":session-admin.stx
Session API Programming
Overview
Developers generally interact with a Session Data Manager
instance in order to make use of sessioning in Zope. Methods
named in this section are those of session data managers unless
otherwise specified.
All of the methods implemented by Session Data Managers, Session
Id Managers and Session Data objects are fully documented in the
"SessioningInterfaces.py" file accompanying this software.
This section of the documentation will concentrate on explaining
common operations having to do with session-tracking and why
they might be important to you.
Terminology
Here's a mini-glossary of terminology used by the session
tracking product:
token (aka 'token value') -- the string or integer used to
represent a single anonymous visitor to the part of the Zope
site managed by a single session id manager.
E.g. "12083789728".
token key namespaces -- the session token key/value pair will
be found in one of these namespaces. They refer to namespaces
codified in the Zope REQUEST object. E.g. "cookies" or
"form".
token key -- the key which is looked for in the REQUEST
namespaces enumerated by the token key namespaces configured.
This references the token as its value. E.g. "_ZopeId".
session data object -- an instance of the session data object
class that is found by asking a transient object container for the
item with a key that is a token value.
Obtaining the Token Value
You can obtain the token value associated with the current
request from a session data manager::
<dtml-var "sessiondatamanager.getToken()">
This snippet will print the token value to the remote browser.
If no token exists for the current request, a new token is
created implicitly and returned.
If you wish to obtain the current token value without implicitly
creating a new token for the current request, you can use the
'create' argument to the 'getToken()' method to suppress this
behavior::
<dtml-var "sessiondatamanager.getToken(create=0)">
This snippet will print a representation of the None value if
there isn't a session token associated with the current request,
or it will print the token value if there is one associated with
the current request. Using 'create=0' is useful if you do not
wish to cause the sessioning machinery to attach a new session
token to the current request, perhaps if you do not wish a
session cookie to be set.
The token value *is not* the session data. The token value
represents the key by which the 'getSessionData' method obtains
a session data object representing the visitor marked by the
token. The token value is either a string or an integer and has
no business meaning. In your code, you should not rely on the
session token composition, length, or type as a result, as it is
subject to change.
Determining Which Token Key Namespace Holds The Session Token
For some applications, it is advantageous to know from which
token key namespace (currently either 'cookies' or 'form') the
token has been gathered. There are two methods of session data
managers which allow you to accomplish this,
'isTokenFromCookie()', and 'isTokenFromForm()'::
<dtml-if "sessiondatamanager.isTokenFromCookie()">
The token came from a cookie.
</dtml-if>
<dtml-if "sessiondatamanager.isTokenFromForm()">
The token came from a form.
</dtml-if>
The 'isTokenFromCookie()' method will return true if the token
in the current request comes from the 'REQUEST.cookies'
namespace. This is true if the token was sent to the Zope
server as a cookie.
The 'isTokenFromForm()' method will return true if the token in
the current request comes from the 'REQUEST.form' namespace.
This is true if the token key/value pair was sent to the Zope
server encoded in a URL or as part of a form element.
If a token doesn't actually exist in the current request when
one of these methods is called, an error will be raised.
During typical operations, you shouldn't need to use these
methods, as you shouldn't care from which REQUEST namespace the
token key/value pair was obtained. However, for highly
customized applications, this pair of methods may be useful.
Obtaining the Token Key/Value Pair and Embedding It Into A Form
You can obtain the "token key" from a session data manager
instance. The token key is the name which is looked for in
token key namespaces by a session id manager. We've already
determined how to obtain the token value. It is useful to
obtain the token key/value pair if you wish to embed a session
token key/value pair as a hidden form field for use in POST
requests::
<html>
<body>
<form action="thenextmethod">
<input type=submit name="submit" value=" GO ">
<input type=hidden name="<dtml-var "sessiondatamanager.getTokenKey()">"
value="<dtml-var "sessiondatamanager.getToken()">">
</form>
</body>
</html>
Determining Whether A Session Token is "New"
A session token is "new" if it has been set in the current
request but has not yet been acknowledged by the client --
meaning it has not been sent back by the client in a request.
This is the case when a new session token is created by the
sessioning machinery due to a call to 'getSessionData()' or
similar as opposed to being received by the sessioning machinery
in a token key namespace. You can use the 'isTokenNew()' method
of session data managers to determine whether the session is
new::
<dtml-if "sessiondatamanager.isTokenNew()">
Token is new.
<dtml-else>
Token is not new.
</dtml-if>
This method may be useful in cases where applications wish to
prevent or detect the regeneration of new tokens when the same
client visits repeatedly without sending back a token in the
request (such as may be the case when a visitor has cookies
"turned off" in their browser and the session id manager only
uses cookies).
If there is no session token associated with the current
request, this method will raise an error.
You shouldn't need to use this method during typical operations,
but it may be useful in advanced applications.
Determining Whether A Session Data Object Exists For The Token Associated
With This Request
If you wish to determine whether a session data object with a
key that is the current request's token exists in the data
manager's associated transient object container, you can use the
'hasSessionData()' method of the session data manager. This
method returns true if there is session data associated with the
current session token::
<dtml-if "sessiondatamanager.hasSessionData()">
The sessiondatamanager object has session data for the token
associated with this request.
<dtml-else>
The sessiondatamanager object does not have session data for
the token associated with this request.
</dtml-if>
The 'hasSessionData()' method is useful in highly customized
applications, but is probably less useful otherwise. It is
recommended that you use 'getSessionData()' instead, allowing
the session data manager to determine whether or not to create a
new data object for the current request.
Embedding A Session Token Into An HTML Link
You can embed the token key/value pair into an HTML link for use
during HTTP GET requests. When a user clicks on a link with a
URL encoded with the session token, the token will be passed
back to the server in the REQUEST.form namespace. If you wish
to use formvar-based session tracking, you will need to encode
all of your "public" HTML links this way. You can use the
'encodeUrl()' method of session data managers in order to
perform this encoding::
<html>
<body>
<a href="<dtml-var "sessiondatamgr.encodeUrl('/amethod')">">Here</a>
is a link.
</body>
</html>
The above dtml snippet will encode the URL "/amethod" (the
target of the word "Here") with the session token key/value pair
appended as a query string. You can additionally pass URLs
which already contain query strings to the 'encodeUrl()' method
successfully.
Obtaining A Session Data Object
Use the 'getSessionData()' method of session data managers to
obtain the session data object associated with the session token
in the current request::
<dtml-let data="sessiondatamanager.getSessionData()">
The 'data' name now refers to a new or existing session data object.
</dtml-let>
The 'getSessionData()' method implicitly creates a new session
token and data object if either does not exist in the current
request. To inhibit this behavior, use the create=0 flag to the
'getSessionData()' method::
<dtml-let data="sessiondatamanager.getSessionData(create=0)">
The 'data' name now refers to an existing session data object or
None if there was no existing token or session data object.
</dtml-let>
The 'getSessionData()' method is a highly used method. It is
probably the most-commonly used method of session data managers.
Modifying A Session Data Object
Once you've used 'getSessionData()' to obtain a session data
object, you can set key/value pairs of the returned session data
object. These key/value pairs are where you store information
related to a particular anonymous visitor. You can use the
'set', 'get', and 'has_key' methods of session data objects to
perform actions related to it::
<dtml-let data="sessiondatamanager.getSessionData()">
<dtml-call "data.set('foo', 'bar')">
<dtml-comment>Set 'foo' key to 'bar' value.</dtml-comment>
<dtml-var "data.get('foo')">
<dtml-comment>Will print 'bar'</dtml-comment>
<dtml-if "data.has_key('foo')">
This will be printed.
<dtml-else>
This will not be printed.
</dtml-if>
</dtml-let>
An essentially arbtrary set of key/value pairs can be placed
into a session data object. Keys and values can be any kinds of
Python objects (note: see Concepts and Caveats section for
exceptions to this rule). The transient object container which
houses the session data object determines its expiration policy.
Session data objects will be available across client requests
for as long as they are not expired.
Manually Invalidating A Session Data Object
Developers can manually invalidate a session data object. When
a session data object is invalidated, it will be flushed from
the system, and will not be returned on subsequent requests to
'getSessionData()'. The 'invalidate()' method of a session data
object causes this to happen::
<dtml-let data="sessiondatamanager.getSessionData()">
<dtml-call "data.invalidate()">
</dtml-let>
Overview
Subsequent calls to 'getSessionData()' in this same request will
return a new session data object. Manual invalidation of
session data is useful in cases where you know the session data
is stale and you wish to flush it from the data manager.
Developers generally *not* interact directly with a Session Data
Manager instance in order to make use of sessioning in Zope.
Manually Invalidating A Session Token Cookie
All of the methods implemented by Session Data Managers, and
Browser Id Managers are fully documented in the
Session API in the "See Also" section below.
Developers may manually invalidate the cookie associated with
the session token, if any. To do so, they can use the
'flushTokenCookie()' method of a session data manager. For
example::
Common Programming
<dtml-call "sessiondatamanager.flushTokenCookie()">
Generally, instead of directly interacting with the session data
manager, you use it's built in traversal feature to put a SESSION
object in the REQUEST. This is simple, and fairly intuitive.
For example, in DTML you might::
If the 'cookies' namespace isn't a valid token key namespace
when this call is performed, an exception will be raised.
<dtml-with SESSION mapping>
<dtml-var cart missing="You have no cart">
</dtml-with>
An Example Of Using Session Data from DTML
or even more simply::
An example of obtaining a session data object from a session
data manager named 'sessiondatamgr' and setting one of its
key-value pairs in DTML follows::
<dtml-var SESSION>
<dtml-with sessiondatamgr>
<dtml-let a=getSessionData>
Before change: <dtml-var a><br>
<dtml-call "a.set('zopetime', ZopeTime())">
<dtml-comment>
'zopetime' will be set to a datetime object for the current
session
</dtml-comment>
After change: <dtml-var a><br>
</dtml-let>
</dtml-with>
This would print the cart object in the session, or the entire SESSION
object. You could set an
object in the session similarly to how you set it in the REQUEST::
The first time you run this method, the "before change"
representation of the session data object will be that of an
empty dictionary, and the "after change" representation will
show a key/value pair of 'zopetime' associated with a DateTime
object. Assuming you've configured your session id manager with
cookies and they're working on your browser properly, the second
and subsequent times you view this method, the "before change"
representation of the session data object will have a datetime
object in it that was the same as the last call's "after change"
representation of the same session data object. This
demonstrates the very basics of session management, because it
demonstrates that we are able to associate an object (the
session data object obtained via getSessionData) with an
anonymous visitor between HTTP requests.
<dtml-call expr="SESSION.set('cart','this is really more of a wagon')">
NOTE: To use this method in conjunction with formvar-based
sessioning, you'd need to encode a link to its URL with the
session token by using the session data manager's 'encodeUrl()'
method.
You adjust the name of the SESSION object in the management screens
for the session data object. You can do more complex operations on
SESSION data with python scripts, e.g.::
Using the 'mapping' Keyword With A Session Data Object in a 'dtml-with'
session = context.REQUEST.SESSION
DTML has the facility to treat a session data object as a
mapping, making it easier to spell some of the more common
methods of access to session data objects. The 'mapping'
keyword to dtml-with means "treat name lookups that follow
this section as queries to my contents by name." For
example::
cart = session.get('cart',()) # Get our cart or an empty list
cart.append(('my line item',100.00))
<dtml-let a="sm.getSessionData()">
<dtml-call "a.set('zopetime', ZopeTime())">
<dtml-comment>
'zopetime' will be set to a datetime object for the current
session... the "set" it calls is the set method of the
session data object.
</dtml-comment>
</dtml-let>
session['cart'] = cart # force a save back to the session
<dtml-with "sm.getSessionData()" mapping>
<dtml-var zopetime>
<dtml-comment>
'dtml-var zopetime' will print the DateTime object just set
because we've used the mapping keyword to map name lookups
into the current session data object.
</dtml-comment>
</dtml-with>
Using Session Data From Python
In general, it is better to put manipulation of data in the session in
a python script than it is to do it via DTML or a page template; while
the latter is possible, it would be far better to simply place a session
management call at the top of any page which requires manipulation of
session data.
Here's an example of using a session data manager and session
data object from a set of Python external methods::
Tips
import time
def setCurrentTime(self):
sessiondatamgr = self.sessiondatamgr
a = sessiondatamgr.getSessionData()
a.set('thetime', time.time())
Keep in mind that SESSION objects (Which are really Transient Objects)
are basically dictionaries; if you wish to iterate through them in the
context of a DTML-IN expression, you should use something like::
def getLastTime(self):
sessiondatamgr = self.sessiondatamgr
a = sessiondatamgr.getSessionData()
return a.get('thetime')
<dtml-in expr="SESSION.items()">
<dtml-var sequence-key>: <dtml-var sequence-item>
</dtml-in>
See Also
......@@ -372,4 +65,4 @@ See Also
- "Session Tracking":Sessions.stx
- "Session Administration":session-admin.stx
- "Transient Object API":../../Transience/Help/TransienceInterfaces.py
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment