1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
<title>Twisted Documentation: Storing Objects in the Session</title>
4
<link href="../stylesheet.css" rel="stylesheet" type="text/css"/>
8
<h1 class="title">Storing Objects in the Session</h1>
9
<div class="toc"><ol/></div>
13
<p>This example shows you how you can persist objects across requests in the
16
<p>As was discussed <a href="session-basics.html" shape="rect">previously</a>, instances
17
of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Session.html" title="twisted.web.server.Session">Session</a></code> last as long as
18
the notional session itself does. Each time <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.server.Request.getSession.html" title="twisted.web.server.Request.getSession">Request.getSession</a></code> is called, if the session
19
for the request is still active, then the same <code>Session</code> instance is
20
returned as was returned previously. Because of this, <code>Session</code>
21
instances can be used to keep other objects around for as long as the session
24
<p>It's easier to demonstrate how this works than explain it, so here's an
27
<pre class="shell" xml:space="preserve">
28
>>> from zope.interface import Interface, Attribute, implements
29
>>> from twisted.python.components import registerAdapter
30
>>> from twisted.web.server import Session
31
>>> class ICounter(Interface):
32
... value = Attribute("An int value which counts up once per page view.")
34
>>> class Counter(object):
35
... implements(ICounter)
36
... def __init__(self, session):
39
>>> registerAdapter(Counter, Session, ICounter)
40
>>> ses = Session(None, None)
41
>>> data = ICounter(ses)
42
>>> print data
43
<__main__.Counter object at 0x8d535ec>
44
>>> print data is ICounter(ses)
49
<p><i>What?</i>, I hear you say.</p>
51
<p>What's shown in this example is the interface and adaption-based API which
52
<code>Session</code> exposes for persisting state. There are several critical
53
pieces interacting here:</p>
56
<li><code>ICounter</code> is an interface which serves several purposes. Like
57
all interfaces, it documents the API of some class of objects (in this case,
58
just the <code>value</code> attribute). It also serves as a key into what is
59
basically a dictionary within the session object: the interface is used to
60
store or retrieve a value on the session (the <code>Counter</code> instance,
62
<li><code>Counter</code> is the class which actually holds the session data in
63
this example. It implements <code>ICounter</code> (again, mostly for
64
documentation purposes). It also has a <code>value</code> attribute, as the
65
interface declared.</li>
66
<li>The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.components.registerAdapter.html" title="twisted.python.components.registerAdapter">registerAdapter</a></code> call sets up the
67
relationship between its three arguments so that adaption will do what we
68
want in this case.</li>
69
<li>Adaption is performed by the expression <code>ICounter(ses)</code>. This
70
is read as <i>adapt <code>ses</code> to <code>ICounter</code></i>. Because
71
of the <code>registerAdapter</code> call, it is roughly equivalent
72
to <code>Counter(ses)</code>. However (because of certain
73
things <code>Session</code> does), it also saves the <code>Counter</code>
74
instance created so that it will be returned the next time this adaption is
75
done. This is why the last statement produces <code>True</code>.</li>
78
<p>If you're still not clear on some of the details there, don't worry about it
79
and just remember this: <code>ICounter(ses)</code> gives you an object you can
80
persist state on. It can be as much or as little state as you want, and you can
81
use as few or as many different <code>Interface</code> classes as you want on a
82
single <code>Session</code> instance.</p>
84
<p>With those conceptual dependencies out of the way, it's a very short step to
85
actually getting persistent state into a Twisted Web application. Here's an
86
example which implements a simple counter, re-using the definitions from the
89
<pre class="python"><p class="py-linenumber">1
97
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span>
99
<span class="py-src-keyword">class</span> <span class="py-src-identifier">CounterResource</span>(<span class="py-src-parameter">Resource</span>):
100
<span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
101
<span class="py-src-variable">session</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>()
102
<span class="py-src-variable">counter</span> = <span class="py-src-variable">ICounter</span>(<span class="py-src-variable">session</span>)
103
<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span> += <span class="py-src-number">1</span>
104
<span class="py-src-keyword">return</span> <span class="py-src-string">"Visit #%d for you!"</span> % (<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span>,)
107
<p>Pretty simple from this side, eh? All this does is
108
use <code>Request.getSession</code> and the adaption from above, plus some
109
integer math to give you a session-based visit counter.</p>
111
<p>Here's the complete source for an <a href="rpy-scripts.html" shape="rect">rpy script</a>
112
based on this example:</p>
114
<pre class="python"><p class="py-linenumber"> 1
139
</p><span class="py-src-variable">cache</span>()
141
<span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Interface</span>, <span class="py-src-variable">Attribute</span>, <span class="py-src-variable">implements</span>
142
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span>.<span class="py-src-variable">components</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">registerAdapter</span>
143
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">server</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Session</span>
144
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">resource</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Resource</span>
146
<span class="py-src-keyword">class</span> <span class="py-src-identifier">ICounter</span>(<span class="py-src-parameter">Interface</span>):
147
<span class="py-src-variable">value</span> = <span class="py-src-variable">Attribute</span>(<span class="py-src-string">"An int value which counts up once per page view."</span>)
149
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
150
<span class="py-src-variable">implements</span>(<span class="py-src-variable">ICounter</span>)
151
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">session</span>):
152
<span class="py-src-variable">self</span>.<span class="py-src-variable">value</span> = <span class="py-src-number">0</span>
154
<span class="py-src-variable">registerAdapter</span>(<span class="py-src-variable">Counter</span>, <span class="py-src-variable">Session</span>, <span class="py-src-variable">ICounter</span>)
156
<span class="py-src-keyword">class</span> <span class="py-src-identifier">CounterResource</span>(<span class="py-src-parameter">Resource</span>):
157
<span class="py-src-keyword">def</span> <span class="py-src-identifier">render_GET</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">request</span>):
158
<span class="py-src-variable">session</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>()
159
<span class="py-src-variable">counter</span> = <span class="py-src-variable">ICounter</span>(<span class="py-src-variable">session</span>)
160
<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span> += <span class="py-src-number">1</span>
161
<span class="py-src-keyword">return</span> <span class="py-src-string">"Visit #%d for you!"</span> % (<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span>,)
163
<span class="py-src-variable">resource</span> = <span class="py-src-variable">CounterResource</span>()
166
<p>One more thing to note is the <code>cache()</code> call at the top of this
167
example. As with the <a href="http-auth.html" shape="rect">previous example</a> where this
168
came up, this rpy script is stateful. This time, it's the <code>ICounter</code>
170
<code>registerAdapter</code> call that need to be executed only once. If we
171
didn't use <code>cache</code>, every request would define a new, different
172
interface named <code>ICounter</code>. Each of these would be a different key in
173
the session, so the counter would never get past one.</p>
177
<p><a href="../index.html">Index</a></p>
178
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'