Personal tools

Views

用函数定义视图;把视图映射为URL;Model接口;view zcml;请求类型;安全性;转向;静态内容

翻译: Jim Zhan ijwing at gmail.com

视图

view 是当请求进入应用时被调用的可执行函数。 repoze.bfg 的主要工作就是 当 request 到达时查找并调用视图。视图的返回值必须实现 WebOb Response 的对象接口。

用函数定义视图

定义视图最简单的方法就是创建一个接收 contextrequest 这两个 参数的函数。譬如,以下就是一个 hello world 的实现:

def hello_world(context, request):
    from webob import Response
    return Repsonse('Hello world!')

contextrequest 的定义如下:

context
通过图遍历(traversal)或 URL 分发查找得到的模型实例。
request
WebOb request 对象,表示当前 WSGI 请求。

视图必须返回一个实现了 WebOb Response 接口的对象。最简单的方法就是 返回一个 webob.Response 对象。但任何包含以下属性的对象也同样有效:

status
response 的 HTTP 状态码(包括名称)。譬如, 200 OK401 Unauthorized
headerlist
需要在 response 中设置 HTTP 报头的元组序列。譬如 [('Content-Type', 'text/html'), ('Content-Length', '412')]
app_iter
一个表示 response 报文的可迭代对象。它可以是一个数组,譬如 ['<html><head></head><body>Hello world!</body></html>'] 或一个类似于文件的对象,又或是其它任何的可迭代对象。

假如视图返回至 repoze.bfg 发佈器的是没有实现这一接口的对象,那么发佈器 将会掷出一个异常。

将视图映射至 URLs

通过在文件 configure.zcml 中使用 ZCML 定义 view 从而 将信息添加至 application registry ,可以将视图和 URL 关联起来。

<view
    for=".models.Hello"
    view=".views.hello_world"
    name="hello.html"
    />

以上就是当 view namehello.html 时是将 .views.hello_world 视图 函数映射至 .models.Hello 所代表的 context Python 对象(或其子类)。

注解

view (如上)中的 forview 属性中句点 (.) 的意思 是“该 ZCML 文件存储路径下 Python 包的相对路径”。因此如果以上的 view 是定义在 hello` 包下的 ``configure.zcml 文件内,你就可以将 相对路径 .models.Hello 改为绝对路径 hello.views.hello_world 。相对或绝对路径在功能上是等价的。但如果包名改变,相对路径通常会更加有用。同时它 也更为简洁。

你也可以为模型定义 default view (默认视图):

<view
    for=".models.Hello"
    view=".views.hello_world"
    />

default view 没有 name 属性。当 context 被遍历后而当前请求没有 view name 时,*default view* 就会被启用。

你也可以通过在 for 属性中使用特殊字符 * 来声明该视图适用于所有的 model 类型。

<view
    for="*"
    view=".views.hello_world"
    name="hello.html"
    />

这表示当 repoze.bfg 识别到 view namehello.html 的*任何* context 后,该视图就会被调动。

注解

如果你对 ZCML 不感冒, 又或者你只是更喜欢用 Python 定义视图,你 可以使用 repoze.bfg.convention 。这个包提供了一个名为 bfg_view 的 decorator,它可以通过 BFG 视图而不是需要依赖于 ZCML 关联至 for, name, permissionrequest_type 信息。你只需在 configure.zcml 中 添加一段 ZCML 定义就可以让 repoze.bfg.convention 查找到所有使用了 该 decorator 的视图。

使用模型接口

除用 for 为 Python 类注册视图外,你还可以为 interface 注册视图。由 于接口可以被关联至任何实例(而非仅由它的类指明其身份),使用接口可为模型的两个或以上的 不同实现间共享视图提供更大的灵活性。譬如,如果两个不同的 Python 模型对象共享一个接口, 那么你就可以使用基于它们其中的任意一个来使用相同的视图。

为了在视图分发时使用接口,你必需先创建一个接口,然后在你的类或实例中标明引用至该接口的 定义。

要将接口关联至类,你需要先定义好接口然后用函数 zope.interface.implements 将 两者关联起来。

from zope.interface import Interface
from zope.interface import implements

class IHello(Interface):
    """ A marker interface """

class Hello(object):
    implements(IHello)

要将接口关联至实例,你需要先定义好接口然后用函数 zope.interface.alsoProvides 将两者关联起来。这个函数通过改变实例来将接口和实例关联起来。

from zope.interface import Interface
from zope.interface import implements

class IHello(Interface):
    """ A marker interface """

class Hello(object):
    pass

def make_hello():
    hello = Hello()
    alsoProviders(hello, IHello)
    return hello

无论你如何将接口关联至实例或类,得到的接口与视图关联的 ZCML 定义都是一样的。假设以上 代码所定义的 IHello 接口在你应用的根部,它的模块名为 "model.py",那以下的接口 定义则会将 .views.hello_world 视图关联至实现(也称为提供)了这个接口的 model。

<view
    for=".models.IHello"
    view=".views.hello_world"
    name="hello.html"
    />

每当 model 被确定为提供这个接口的 context 时,它就会根据 URL 查找名为 hello.html 的视图,继而调用 .view.hello_world

注意,当出现视图同时被注册为类和接口所用这样的二义性时,类定义具有优先权。

在术语集中可以找到更多关于 interface 的定义。

ZCML 的中 view 元件

ZCML 的 view 元件具有以下的属性:

view
Python 句点形式的视图函数名。
for
Python 句点形式的路径名。其 context 必须为该 Python 类的实例或是提供了 接口 ,以让视图查找及调用。
name
view name 。你可以通过 traversal 这章来了解这一概念。
permission
要调用视图,用户必须拥有 permission 名称(权限名)。
request_type
为让该视图能被查找及调用,:term:request 必须拥有的以 Python 句点形式表示的 interface 名称。:ref:view_security_section 可查找到更多关于安 全和权限的信息。

视图的请求类型

你可以选择性的将 request_type 属性添加到 view 定义中,从而指定视图的请求类型。 譬如:

<view
    for=".models.IHello"
    view=".views.hello_json"
    name="hello.json"
    request_type=".interfaces.IJSONRequest"
    />

.interfaces.IJSONRequest 代码大致如下:

from repoze.bfg.interfaces import IRequest

class IJSONRequest(IRequest):
    """ An marker interface for representing a JSON request """

这是一个使用 JSON 的简单请求。为确保当(且仅当)请求来自于 JSON 客户端时该视图才会被调用, 你可以用 INewRequest 事件记录器将 IJSONRequest 接口关联至该请求。由于我们 在 ZCML 里已经指明了这个视图的 request_type.interface.IJSONRequest, 所以只有当请求提供了这一接口时,该视图才会被调用。

通过请求参数,你也可以使用这个接口来改变请求所提供的接口。

通过将经主机名验证的任意接口或是 INewRequest 事件记录器内 request 中的任何 信息关联至 request,你就可以精确的控制视图的定位。譬如,如果你需要为两个不同主机名 的 request 准备两个区别不大的视图,你可以将其中一个视图的 request_type 定义 为 .interfaces.IHostnameFoo 而另一个为 .interfaces.IHostnameBar``, 然后在事件记录器中将 ``.interfaces.IHostnameFoo 与 HTTP_POST 为 foo 时的 request 以及 .interfaces.IHostnameBar 与 HTTP_Post 为 bar 时的 request 关联起来,那么当请求到达时的系统就会调用相应的视图。

你也可以建立一个独立于 request_type 的继承体系。当 repoze.bfg 查找 视图时,通过该接口的类层次体系,基于标准 Python 函数定位顺序的请求就会找到最适用于该 接口的视图。

注解

events_chapter 有更多关于事件记录器的信息,以及如何为 request 供不同的类型。

视图安全

如果 :term:security policy` 为激活状态,系统会先检查 ``viewpermission`,以确保视图函数在被调用前,当前授权用户拥有此权限。以下是一个在 ``view` 中定义权限的例子:

<view
    for=".models.IBlob"
    view=".views.add_entry"
    name="add.html"
    permission="add"
    />

启用安全策略后,这个视图会被 add 权限所保护。如果用户在当前的 context 下没有 add 权限,视图就不会被调用,系统会将 HTTP 状态码 Unauthorized 返 回给客户端。

注解

security_chapter 一章有说明如何启用安全策略。

使用视图来进行 HTTP 重定向

通过返回不同的响应,你可以在视图中创建 HTTP 重定向。

from webob.exc import HTTPFound

def myview(context, request):
    return HTTPFound(location='http://example.com')

webob.exc 模块中所有的异常均实现了 IResponse 这一接口;它们都可以在 视图中作为 response 被返回。 请查阅 WebOb 中该模块的文档;它包括了如 Unauthorized 等的其它响应类型。

使用视图处理静态资源

repoze.bfg 中,处理静态资源(如 JavaScript 和 CSS 文件)的首选是 :mod:repoze.bfg.view static 辅助类。这个类可以创建一个类似于 repoze.bfg 视图的可调用函数来处理目录中的静态资源。譬如,要处理在应用中 被挂载到 URL 路径 /static 的文件系统目录 /path/to/static/dir ,首先 在应用程序根目录下的 static.py 文件内创建一个 repoze.bfg.view 的 实例如下:

from repoze.bfg.view import static
static_view = static('/path/to/static/dir')

然后,通过 ZCML (应用中的 configure.zcml 文件) 用表示根对象的类或接口将 这个视图映射到 /static

<view
    for=".models.Root"
    view=".static.static_view"
    name="static"
    />

本例中,引用至 BFG 应用根对象的类的 .model.Root 是一个实例。

注解

如果想通过任意 model 对象将 static 当作静态视图来访问,你可以将 for 的值设为 * 。它会允许 /static/foo.js ,但 /anything/static/foo.js 也同样有效,只要 anything 本身是可以解析的。

现在,将你的静态文件(如 JS)放到文件系统目录中(如 /path/to/static/dir 。这步 完成后,你应该就可以通过添加了 /static 前缀的 URLs 浏览这个目录下的静态文件了, 譬如,``/static/foo.js`` 会返回 /path/to/static/dir/foo.js 。静态目录 可以递归的包含子目录,而任何的子目录都可以存放文件;它们会如你所想那样的为静态视图所解析。

注解

为确保根目录中的 model 对象不会屏蔽静态资源 (在遍历的过程中 model 对象 的优先级较高),或根对象的 __getitem__ 函数在静态资源请求到达时不被调用,你 可以使用 URL 引用以上的静态资源,如 /@@static/foo.js 。它和 /static/foo.js 完全等价的。:ref::traversal_chapter 一章有关于 @@ 的说明。

注解

在底层,``repoze.bfg.view.static`` 使用 urlparser.StaticURLParser WSGI 应用程序来处理静态文件。`the Paste documentation for urlparser <http://pythonpaste.org/modules/urlparser.html>`_ 有关于 urlparser.StaticURLParser 更多的信息。

 

本站由 润普公司资助, 采用 易度CMS 构建。

广而告之:润普公司 易度云办公平台,包括 易度文档管理系统 易度项目管理系统 , 易度部门管理 ,均采用Zope 3/BFG技术开发。
沪ICP备05008050