/usr/share/doc/python-twisted-web/howto/web-in-60/session-store.html is in python-twisted-web 12.0.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | <?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">
<head>
<title>Twisted Documentation: Storing Objects in the Session</title>
<link href="../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body bgcolor="white">
<h1 class="title">Storing Objects in the Session</h1>
<div class="toc"><ol/></div>
<div class="content">
<span/>
<p>This example shows you how you can persist objects across requests in the
session object.</p>
<p>As was discussed <a href="session-basics.html" shape="rect">previously</a>, instances
of <code class="API"><a href="http://twistedmatrix.com/documents/12.0.0/api/twisted.web.server.Session.html" title="twisted.web.server.Session">Session</a></code> last as long as
the notional session itself does. Each time <code class="API"><a href="http://twistedmatrix.com/documents/12.0.0/api/twisted.web.server.Request.getSession.html" title="twisted.web.server.Request.getSession">Request.getSession</a></code> is called, if the session
for the request is still active, then the same <code>Session</code> instance is
returned as was returned previously. Because of this, <code>Session</code>
instances can be used to keep other objects around for as long as the session
exists.</p>
<p>It's easier to demonstrate how this works than explain it, so here's an
example:</p>
<pre class="shell" xml:space="preserve">
>>> from zope.interface import Interface, Attribute, implements
>>> from twisted.python.components import registerAdapter
>>> from twisted.web.server import Session
>>> class ICounter(Interface):
... value = Attribute("An int value which counts up once per page view.")
...
>>> class Counter(object):
... implements(ICounter)
... def __init__(self, session):
... self.value = 0
...
>>> registerAdapter(Counter, Session, ICounter)
>>> ses = Session(None, None)
>>> data = ICounter(ses)
>>> print data
<__main__.Counter object at 0x8d535ec>
>>> print data is ICounter(ses)
True
>>>
</pre>
<p><i>What?</i>, I hear you say.</p>
<p>What's shown in this example is the interface and adaption-based
API which <code>Session</code> exposes for persisting state. There are
several critical pieces interacting here:</p>
<ul>
<li><code>ICounter</code> is an interface which serves several purposes. Like
all interfaces, it documents the API of some class of objects (in this case,
just the <code>value</code> attribute). It also serves as a key into what is
basically a dictionary within the session object: the interface is used to
store or retrieve a value on the session (the <code>Counter</code> instance,
in this case).</li>
<li><code>Counter</code> is the class which actually holds the session data in
this example. It implements <code>ICounter</code> (again, mostly for
documentation purposes). It also has a <code>value</code> attribute, as the
interface declared.</li>
<li>The <code class="API"><a href="http://twistedmatrix.com/documents/12.0.0/api/twisted.python.components.registerAdapter.html" title="twisted.python.components.registerAdapter">registerAdapter</a></code> call sets up the
relationship between its three arguments so that adaption will do what we
want in this case.</li>
<li>Adaption is performed by the expression <code>ICounter(ses)</code>. This
is read as : adapt <code>ses</code> to <code>ICounter</code>. Because
of the <code>registerAdapter</code> call, it is roughly equivalent
to <code>Counter(ses)</code>. However (because of certain
things <code>Session</code> does), it also saves the <code>Counter</code>
instance created so that it will be returned the next time this adaption is
done. This is why the last statement produces <code>True</code>.</li>
</ul>
<p>If you're still not clear on some of the details there, don't worry about it
and just remember this: <code>ICounter(ses)</code> gives you an object you can
persist state on. It can be as much or as little state as you want, and you can
use as few or as many different <code>Interface</code> classes as you want on a
single <code>Session</code> instance.</p>
<p>With those conceptual dependencies out of the way, it's a very short step to
actually getting persistent state into a Twisted Web application. Here's an
example which implements a simple counter, re-using the definitions from the
example above:</p>
<pre class="python"><p class="py-linenumber">1
2
3
4
5
6
7
8
</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>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">CounterResource</span>(<span class="py-src-parameter">Resource</span>):
<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>):
<span class="py-src-variable">session</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>()
<span class="py-src-variable">counter</span> = <span class="py-src-variable">ICounter</span>(<span class="py-src-variable">session</span>)
<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span> += <span class="py-src-number">1</span>
<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>,)
</pre>
<p>Pretty simple from this side, eh? All this does is
use <code>Request.getSession</code> and the adaption from above, plus some
integer math to give you a session-based visit counter.</p>
<p>Here's the complete source for an <a href="rpy-scripts.html" shape="rect">rpy script</a>
based on this example:</p>
<pre class="python"><p class="py-linenumber"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
</p><span class="py-src-variable">cache</span>()
<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>
<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>
<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>
<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>
<span class="py-src-keyword">class</span> <span class="py-src-identifier">ICounter</span>(<span class="py-src-parameter">Interface</span>):
<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>)
<span class="py-src-keyword">class</span> <span class="py-src-identifier">Counter</span>(<span class="py-src-parameter">object</span>):
<span class="py-src-variable">implements</span>(<span class="py-src-variable">ICounter</span>)
<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>):
<span class="py-src-variable">self</span>.<span class="py-src-variable">value</span> = <span class="py-src-number">0</span>
<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>)
<span class="py-src-keyword">class</span> <span class="py-src-identifier">CounterResource</span>(<span class="py-src-parameter">Resource</span>):
<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>):
<span class="py-src-variable">session</span> = <span class="py-src-variable">request</span>.<span class="py-src-variable">getSession</span>()
<span class="py-src-variable">counter</span> = <span class="py-src-variable">ICounter</span>(<span class="py-src-variable">session</span>)
<span class="py-src-variable">counter</span>.<span class="py-src-variable">value</span> += <span class="py-src-number">1</span>
<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>,)
<span class="py-src-variable">resource</span> = <span class="py-src-variable">CounterResource</span>()
</pre>
<p>One more thing to note is the <code>cache()</code> call at the top
of this example. As with the <a href="http-auth.html" shape="rect">previous
example</a> where this came up, this rpy script is stateful. This
time, it's the <code>ICounter</code> definition and
the <code>registerAdapter</code> call that need to be executed only
once. If we didn't use <code>cache</code>, every request would define
a new, different interface named <code>ICounter</code>. Each of these
would be a different key in the session, so the counter would never
get past one.</p>
</div>
<p><a href="../index.html">Index</a></p>
<span class="version">Version: 12.0.0</span>
</body>
</html>
|