在会话中存储对象¶
此示例展示了如何在会话对象中跨请求持久化对象。
如之前所述,Session
实例的持续时间与假想会话本身的持续时间相同。每次调用Request.getSession
时,如果请求的会话仍然处于活动状态,则会返回与之前返回的相同的Session
实例。因此,Session
实例可用于在会话存在期间保留其他对象。
演示如何实现比解释更容易,因此以下是一个示例
>>> from zope.interface import Interface, Attribute, implementer
>>> 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.")
...
>>> @implementer(ICounter)
... class Counter(object):
... 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
>>>
什么?,我听到你说。
此示例中显示的是Session
用于持久化状态的接口和基于适配器的 API。这里有几个关键部分在交互
ICounter
是一个接口,它有多种用途。与所有接口一样,它记录了一类对象的 API(在本例中,只是value
属性)。它还用作会话对象中基本上是一个字典的键:该接口用于在会话中存储或检索值(在本例中为Counter
实例)。Counter
是一个类,它实际上在此示例中保存会话数据。它实现了ICounter
(同样,主要是为了文档目的)。它还有一个value
属性,如接口所声明的那样。registerAdapter
调用设置了其三个参数之间的关系,以便适配将按照我们在此情况下的预期执行。适配由表达式
ICounter(ses)
执行。这可以理解为:将ses
适配为ICounter
。由于registerAdapter
调用,它大致等效于Counter(ses)
。但是(由于Session
执行的某些操作),它还保存了创建的Counter
实例,以便在下一次执行此适配时返回它。这就是为什么最后一个语句产生True
的原因。
如果您仍然不清楚其中的一些细节,请不要担心,只需记住这一点:ICounter(ses)
会为您提供一个可以在其上持久化状态的对象。它可以是您想要的任何状态,无论多少,您可以在单个Session
实例上使用任意数量的不同Interface
类。
在这些概念依赖关系之外,将持久化状态实际添加到 Twisted Web 应用程序中只是一小步。以下是一个实现简单计数器的示例,它重用了上面示例中的定义
from twisted.web.resource import Resource
class CounterResource(Resource):
def render_GET(self, request):
session = request.getSession()
counter = ICounter(session)
counter.value += 1
return (b"<!DOCTYPE html><html><head><meta charset='utf-8'>"
b"<title></title></head><body>"
b"Visit #" + str(counter.value).encode("utf-8") +
b" for you!")
从这一方面来看非常简单,对吧?它所做的只是使用Request.getSession
和上面的适配,加上一些整数运算,为您提供基于会话的访问计数器。
以下是一个基于此示例的rpy 脚本 的完整源代码
cache()
from zope.interface import Interface, Attribute, implementer
from twisted.python.components import registerAdapter
from twisted.web.server import Session
from twisted.web.resource import Resource
class ICounter(Interface):
value = Attribute("An int value which counts up once per page view.")
@implementer(ICounter)
class Counter(object):
def __init__(self, session):
self.value = 0
registerAdapter(Counter, Session, ICounter)
class CounterResource(Resource):
def render_GET(self, request):
session = request.getSession()
counter = ICounter(session)
counter.value += 1
return (b"<!DOCTYPE html><html><head><meta charset='utf-8'>"
b"<title></title></head><body>"
b"Visit #" + str(counter.value).encode("utf-8") +
b" for you!")
resource = CounterResource()
还有一点需要注意的是此示例顶部的cache()
调用。与之前的示例 中出现此调用一样,此 rpy 脚本是有状态的。这一次,是ICounter
定义和registerAdapter
调用只需要执行一次。如果我们不使用cache
,每个请求都会定义一个新的、不同的名为ICounter
的接口。这些中的每一个都将是会话中的一个不同的键,因此计数器永远不会超过 1。