Initial import to Tizen
[profile/ivi/python-twisted.git] / doc / web / howto / web-in-60 / session-store.html
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">
2   <head>
3 <title>Twisted Documentation: Storing Objects in the Session</title>
4 <link href="../stylesheet.css" rel="stylesheet" type="text/css"/>
5   </head>
6
7   <body bgcolor="white">
8     <h1 class="title">Storing Objects in the Session</h1>
9     <div class="toc"><ol/></div>
10     <div class="content">
11 <span/>
12
13 <p>This example shows you how you can persist objects across requests in the
14 session object.</p>
15
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/12.1.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/12.1.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
22 exists.</p>
23
24 <p>It's easier to demonstrate how this works than explain it, so here's an
25 example:</p>
26
27 <pre class="shell" xml:space="preserve">
28 &gt;&gt;&gt; from zope.interface import Interface, Attribute, implements
29 &gt;&gt;&gt; from twisted.python.components import registerAdapter
30 &gt;&gt;&gt; from twisted.web.server import Session
31 &gt;&gt;&gt; class ICounter(Interface):
32 ...     value = Attribute(&quot;An int value which counts up once per page view.&quot;)
33 ...
34 &gt;&gt;&gt; class Counter(object):
35 ...     implements(ICounter)
36 ...     def __init__(self, session):
37 ...         self.value = 0
38 ...
39 &gt;&gt;&gt; registerAdapter(Counter, Session, ICounter)
40 &gt;&gt;&gt; ses = Session(None, None)
41 &gt;&gt;&gt; data = ICounter(ses)
42 &gt;&gt;&gt; print data
43 &lt;__main__.Counter object at 0x8d535ec&gt;
44 &gt;&gt;&gt; print data is ICounter(ses)
45 True
46 &gt;&gt;&gt;
47 </pre>
48
49 <p><i>What?</i>, I hear you say.</p>
50
51 <p>What's shown in this example is the interface and adaption-based
52 API which <code>Session</code> exposes for persisting state. There are
53 several critical pieces interacting here:</p>
54
55 <ul>
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,
61     in this case).</li>
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/12.1.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 : adapt <code>ses</code> to <code>ICounter</code>. 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>
76 </ul>
77
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>
83
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
87 example above:</p>
88
89 <pre class="python"><p class="py-linenumber">1
90 2
91 3
92 4
93 5
94 6
95 7
96 8
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>
98
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">&quot;Visit #%d for you!&quot;</span> % (<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span>,)
105 </pre>
106
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>
110
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>
113
114 <pre class="python"><p class="py-linenumber"> 1
115  2
116  3
117  4
118  5
119  6
120  7
121  8
122  9
123 10
124 11
125 12
126 13
127 14
128 15
129 16
130 17
131 18
132 19
133 20
134 21
135 22
136 23
137 24
138 25
139 </p><span class="py-src-variable">cache</span>()
140
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>
145
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">&quot;An int value which counts up once per page view.&quot;</span>)
148
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>
153
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>)
155
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">&quot;Visit #%d for you!&quot;</span> % (<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span>,)
162
163 <span class="py-src-variable">resource</span> = <span class="py-src-variable">CounterResource</span>()
164 </pre>
165
166 <p>One more thing to note is the <code>cache()</code> call at the top
167 of this example. As with the <a href="http-auth.html" shape="rect">previous
168 example</a> where this came up, this rpy script is stateful. This
169 time, it's the <code>ICounter</code> definition and
170 the <code>registerAdapter</code> call that need to be executed only
171 once. If we didn't use <code>cache</code>, every request would define
172 a new, different interface named <code>ICounter</code>. Each of these
173 would be a different key in the session, so the counter would never
174 get past one.</p>
175
176 </div>
177
178     <p><a href="../index.html">Index</a></p>
179     <span class="version">Version: 12.1.0</span>
180   </body>
181 </html>