使用事件

事件 是由 Pyramid 框架在应用程序生命周期中的有趣点上。您不需要使用事件来创建 Pyramid 应用程序,但当您希望执行稍微高级的操作时,它们可能很有用。例如,订阅一个事件可以使您在每个新请求的结果中运行一些代码。

事件在 Pyramid 总是由框架广播。但是,只有当您注册 用户 . 订阅服务器是一个接受名为 event

1
2
def mysubscriber(event):
    print(event)

上面是一个订户,它在调用事件时只将它打印到控制台。

然而,仅仅存在订户函数并不足以安排调用它。要安排呼叫订户,您需要使用 pyramid.config.Configurator.add_subscriber() 否则您需要使用 pyramid.events.subscriber() 修饰器修饰通过 scan .

强制配置事件侦听器

您可以通过 add_subscriber() 方法:

1
2
3
4
5
6
7
8
from pyramid.events import NewRequest

from subscribers import mysubscriber

# "config" below is assumed to be an instance of a
# pyramid.config.Configurator object

config.add_subscriber(mysubscriber, NewRequest)

第一个论点 add_subscriber() 是订阅服务器功能(或 dotted Python name 指的是订阅服务器可调用);第二个参数是事件类型。

参见

也见 Configurator .

使用装饰器配置事件侦听器

您可以通过配置订阅服务器函数来为某些事件类型调用 pyramid.events.subscriber() 功能。

1
2
3
4
5
6
from pyramid.events import NewRequest
from pyramid.events import subscriber

@subscriber(NewRequest)
def mysubscriber(event):
    event.request.foo = 1

subscriber() 使用装饰器,a scan 必须对包含修饰函数的包执行,以使修饰程序具有任何效果。

上述任何一个注册示例都意味着 Pyramid 框架发出一个事件对象,该对象提供 pyramid.events.NewRequest 接口 mysubscriber 函数将用 事件 对象。

如您所见,订阅是根据 (如 pyramid.events.NewResponse )发送到订阅服务器的事件对象将始终是具有 interface . 为了 pyramid.events.NewResponse ,该接口是 pyramid.interfaces.INewResponse . 接口文档提供有关事件对象的可用属性和方法的信息。

订阅服务器函数的返回值被忽略。同一事件类型的订阅服务器不保证以任何特定的顺序相互调用。

所有混凝土 Pyramid 事件类型记录在 pyramid.events API文档。

一个例子

如果在 subscribers.py 应用程序中的文件,如下所示:

1
2
3
4
5
def handle_new_request(event):
    print('request', event.request)

def handle_new_response(event):
    print('response', event.response)

通过在应用程序的配置启动中添加以下代码,可以配置这些函数以便在适当的时间调用:

1
2
3
4
5
6
# config is an instance of pyramid.config.Configurator

config.add_subscriber('myproject.subscribers.handle_new_request',
                      'pyramid.events.NewRequest')
config.add_subscriber('myproject.subscribers.handle_new_response',
                      'pyramid.events.NewResponse')

任何一种机制都会导致 subscribers.py 注册为事件订阅服务器。在此配置下,当应用程序运行时,每次检测到新的请求或响应时,都会向控制台打印一条消息。

我们的每个订阅服务器函数都接受 event 对象并打印事件对象的属性。这就引出了一个问题:我们如何知道特定事件具有哪些属性?

我们知道 pyramid.events.NewRequest 事件对象具有 request 属性,它是 request 对象,因为接口定义在 pyramid.interfaces.INewRequest 说是必须的。同样,我们知道 pyramid.interfaces.NewResponse 事件有 response 属性,它是由应用程序构造的响应对象,因为在 pyramid.interfaces.INewResponse 说必须 (pyramid.events.NewResponse 对象还具有 request

创建自己的活动

除了使用金字塔框架创建的事件之外,您还可以创建自己的事件以在应用程序中使用。这对于分离应用程序的各个部分很有用。

例如,假设您的应用程序在创建新文档时必须做许多事情。您可以在视图中创建文档,然后触发自定义事件,而不是将所有这些逻辑放到创建文档的视图中。自定义事件的订户可以采取其他操作,例如索引文档、发送电子邮件或向远程系统发送消息。

事件只是一个对象。自定义事件没有必需的属性或方法。一般来说,您的事件应该跟踪订户需要的信息。下面是一些自定义事件类示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class DocCreated(object):
    def __init__(self, doc, request):
        self.doc = doc
        self.request = request

class UserEvent(object):
    def __init__(self, user):
        self.user = user

class UserLoggedIn(UserEvent):
    pass

一些金字塔应用程序选择在 events 模块。

您可以用与强制订阅金字塔事件或使用装饰器订阅金字塔事件相同的方式订阅自定义事件。您还可以使用自定义事件 subscriber predicates . 下面是使用decorator订阅自定义事件的示例:

1
2
3
4
5
6
7
8
from pyramid.events import subscriber
from .events import DocCreated
from .index import index_doc

@subscriber(DocCreated)
def index_doc(event):
    # index the document using our application's index_doc function
    index_doc(event.doc, event.request)

上面的示例假设应用程序定义了 DocCreated 事件类和 index_doc 功能。

要启动自定义事件,请使用 pyramid.registry.Registry.notify() 方法,最常被访问为 request.registry.notify . 例如:

1
2
3
4
5
6
7
from .events import DocCreated

def new_doc_view(request):
    doc = MyDoc()
    event = DocCreated(doc, request)
    request.registry.notify(event)
    return {'document': doc}

此示例视图将通知自定义 DocCreated 事件。

请注意,当您触发一个事件时,所有订阅服务器都是同步运行的,因此创建可能需要很长时间才能运行的事件处理程序通常不是一个好主意。尽管事件处理程序可以用作在自己的消息队列上生成任务的中心位置。