渲染器

可调用的视图不需要 总是 返回A Response 对象。如果一个视图碰巧返回了一些不实现金字塔响应接口的东西, Pyramid 将尝试使用 renderer 构造一个响应。例如:

1
2
3
4
5
from pyramid.view import view_config

@view_config(renderer='json')
def hello_world(request):
    return {'content':'Hello!'}

上面的示例返回 词典 从视图调用。字典不实现金字塔响应接口,因此您可能认为此示例将失败。但是,由于 renderer 与可通过其调用的视图关联 view configuration (在这种情况下,使用 renderer 参数传递给 view_config() ,如果视图显示 not 返回一个响应对象,渲染器将尝试将视图的结果转换为代表开发人员的响应。

当然,如果没有与视图配置关联的渲染器,则返回除实现响应接口的对象之外的任何内容都将导致错误。如果渲染器 is 使用时,视图返回的内容必须与使用的特定类型的呈现器兼容,否则在视图调用期间可能会发生错误。

有一个例外:它是 总是 确定返回响应对象,即使在 renderer 已配置。在这种情况下,渲染器被完全忽略。

存在各种类型的渲染器,包括使用模板系统的序列化渲染器和渲染器。

正在写入使用渲染器的视图可调用文件

正如我们所看到的,视图可调用并不总是返回响应对象。相反,它可能返回一个任意的python对象,期望 renderer 将以您的名义将该对象转换为响应实例。一些渲染器使用模板系统,而其他渲染器使用对象序列化技术。在实践中,渲染器从python字典获取应用程序数据值,因此在实践中,查看使用渲染器的可调用文件返回python字典。

查看可调用文件 explicitly call 渲染器,但通常不会。相反,视图配置声明用于渲染视图可调用结果的渲染器。这是用 renderer 属性。例如,此调用 add_view() 联想到 json 具有可调用视图的渲染器:

config.add_view('myproject.views.my_view', renderer='json')

将此配置添加到应用程序时, myproject.views.my_view View Callable现在将使用 json 渲染器,它将视图返回值渲染到 JSON 响应序列化。

金字塔定义了几个 内置渲染器 和其他渲染器可以由开发人员根据需要添加到系统中。见 添加和更改渲染器 .

使用呈现器并返回非响应值的视图可以通过将属性附加到 request.response 属性。见 呈现响应的不同属性 .

如前所述,如果 view callableview configuration 返回响应对象(或其实例),与视图配置关联的任何呈现器都将被忽略,并将响应传递回 Pyramid 不变。例如:

1
2
3
4
5
6
from pyramid.response import Response
from pyramid.view import view_config

@view_config(renderer='json')
def view(request):
    return Response('OK') # json renderer avoided

同样地,对于 HTTP exception 回应:

1
2
3
4
5
6
from pyramid.httpexceptions import HTTPFound
from pyramid.view import view_config

@view_config(renderer='json')
def view(request):
    return HTTPFound(location='http://example.com') # json renderer avoided

当然你也可以把 request.response 属性以避免渲染:

1
2
3
4
5
6
from pyramid.view import view_config

@view_config(renderer='json')
def view(request):
    request.response.body = 'OK'
    return request.response # json renderer avoided

内置渲染器

几个内置渲染器存在于 Pyramid . 这些渲染器可用于 renderer 视图配置的属性。

注解

官方支持的模板语言的绑定可以在 可用的附加模板系统绑定 .

string :字符串呈现器

这个 string 渲染器将视图可调用结果呈现为字符串。如果视图可调用返回非响应对象,并且 string 渲染器在该视图的配置中关联,结果是通过python运行对象 str 函数生成字符串。

下面是返回字典的视图示例。如果 string 在该视图的配置中指定了呈现器,该视图将把返回的字典呈现给 str() 词典的表示:

1
2
3
4
5
from pyramid.view import view_config

@view_config(renderer='string')
def hello_world(request):
    return {'content':'Hello!'}

此类视图返回的响应的主体将是一个字符串,该字符串表示 str() 返回值的序列化:

{'content': 'Hello!'}

使用字符串呈现器的视图可以通过使用 request.response 属性。见 呈现响应的不同属性 .

JSON渲染器

这个 json 渲染器将视图可调用结果渲染到 JSON . 默认情况下,它通过 json.dumps 标准库函数,并将结果包装为响应对象。它还将响应内容类型设置为 application/json .

下面是返回字典的视图示例。自从 json 在该视图的配置中指定了呈现器,该视图将把返回的字典呈现为JSON序列化:

1
2
3
4
5
from pyramid.view import view_config

@view_config(renderer='json')
def hello_world(request):
    return {'content':'Hello!'}

此类视图返回的响应正文将是一个字符串,表示返回值的JSON序列化:

{"content": "Hello!"}

返回值不必是字典,但返回值必须包含可由配置的序列化程序序列化的值(默认情况下 json.dumps

您可以通过命名来配置视图以使用JSON呈现器。 json 作为 renderer 视图配置的参数,例如通过使用 add_view()

1
2
3
4
config.add_view('myproject.views.hello_world',
                name='hello',
                context='myproject.resources.Hello',
                renderer='json')

使用JSON呈现器的视图可以通过使用 request.response 属性。见 呈现响应的不同属性 .

序列化自定义对象

默认情况下,有些对象不是JSON可序列化的(例如日期时间和其他任意的Python对象)。但是,可以通过两种方式注册使不可序列化对象可序列化的代码:

  • 定义一个 __json__ 应用程序中对象的方法。
  • 对于您不“拥有”的对象,可以注册一个知道 适配器 对于那种物体。
使用习惯 __json__ 方法

自定义对象可以通过定义一个 __json__ 对象类的方法。此方法应返回本机可序列化的JSON值(如int、list、字典、字符串等)。它应该接受一个附加的论点, request ,它将是呈现时的活动请求对象。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from pyramid.view import view_config

class MyObject(object):
    def __init__(self, x):
        self.x = x

    def __json__(self, request):
        return {'x':self.x}

@view_config(renderer='json')
def objects(request):
    return [MyObject(1), MyObject(2)]

# the JSON value returned by ``objects`` will be:
#    [{"x": 1}, {"x": 2}]
使用 add_adapter 自定义JSON呈现器的方法

如果您不是正在序列化的对象的作者,则不可能(至少不合理)添加自定义 __json__ 方法,以影响序列化。如果传递给呈现器的对象不是可序列化类型,并且没有 __json__ 方法,通常是 TypeError 将在序列化期间引发。您可以通过创建自定义JSON呈现器并添加适配器来处理自定义类型来更改此行为。渲染器将尝试使用注册的适配器来调整不可序列化的对象。下面是一个简短的示例:

1
2
3
4
5
6
7
8
9
from pyramid.renderers import JSON

if __name__ == '__main__':
    config = Configurator()
    json_renderer = JSON()
    def datetime_adapter(obj, request):
        return obj.isoformat()
    json_renderer.add_adapter(datetime.datetime, datetime_adapter)
    config.add_renderer('json', json_renderer)

这个 add_adapter 方法应接受两个参数: 要运行此适配器的对象(在上面的示例中, datetime.datetime )和适配器本身。

适配器应该是可调用的。它应该接受两个参数:需要序列化的对象和 request ,这将是呈现时的当前请求对象。适配器应升高 TypeError 如果它无法确定如何处理对象。

pyramid.renderers.JSON添加和更改渲染器 更多信息。

1.4 新版功能: 序列化自定义对象。

JSONP渲染器

1.1 新版功能.

pyramid.renderers.JSONP 是一个 JSONP 渲染器工厂帮助器,它实现了混合JSON/JSONP渲染器。jsonp对于发出跨域Ajax请求很有用。

与其他渲染器不同,JSONP渲染器需要在启动时“手动”配置。使用配置JSONP渲染器 pyramid.config.Configurator.add_renderer() 方法:

from pyramid.config import Configurator
from pyramid.renderers import JSONP

config = Configurator()
config.add_renderer('jsonp', JSONP(param_name='callback'))

一旦此渲染器通过 add_renderer() 如上所述,您可以使用 jsonp 作为 renderer= 参数到 @view_configpyramid.config.Configurator.add_view()

from pyramid.view import view_config

@view_config(renderer='jsonp')
def myview(request):
    return {'greeting':'Hello world'}

当调用使用JSONP渲染器的视图时:

  • 如果请求的HTTP查询字符串中有参数(aka request.GET )与 param_name 注册的JSONP渲染器(默认情况下, callback ,渲染器将返回JSONP响应。
  • 如果请求的查询字符串中没有回调参数,则渲染器将返回“plain”JSON响应。

Javascript库Ajax功能将帮助您发出JSONP请求。例如,jquery有一个 getJSON function ,并且在其 ajax function .

例如(javascript):

var api_url = 'http://api.geonames.org/timezoneJSON' +
              '?lat=38.301733840000004' +
              '&lng=-77.45869621' +
              '&username=fred' +
              '&callback=?';
jqhxr = $.getJSON(api_url);

callback=? 在上面 url jquery的参数 getJSON 函数向jquery指示查询应作为jsonp请求进行;该 callback 参数将自动为您填写并使用。

中为“普通”JSON呈现器定义的相同自定义对象序列化方案 序列化自定义对象 也可以在将值传递给JSONP呈现器时使用。

呈现响应的不同属性

在由 renderer 返回到 Pyramid ,将检查请求的几个可能影响响应行为的属性。

不直接返回响应的视图可调用文件应使用 pyramid.response.Response 属性,可用为 request.response 在执行过程中,影响相关的响应行为。

例如,如果需要从使用渲染器的可调用视图中更改响应状态,请指定 status 属性 response 返回结果前请求的属性:

1
2
3
4
5
6
from pyramid.view import view_config

@view_config(name='gone', renderer='templates/gone.pt')
def myview(request):
    request.response.status = '404 Not Found'
    return {'URL':request.URL}

注意的突变 request.response 在直接返回响应对象的视图中,除非返回响应对象,否则将不起作用。 is request.response . 例如,下面的示例调用 request.response.set_cookie ,但此调用将无效,因为返回了不同的响应对象。

1
2
3
4
5
from pyramid.response import Response

def view(request):
    request.response.set_cookie('abc', '123') # this has no effect
    return Response('OK') # because we're returning a different response

如果你变异 request.response 你想让突变产生效果,你必须返回 request.response

1
2
3
def view(request):
    request.response.set_cookie('abc', '123')
    return request.response

有关请求属性的更多信息,请参阅中的API文档 pyramid.request . 有关的API的详细信息 request.responsepyramid.request.Request.response .

添加和更改渲染器

新的模板系统和序列化程序可以与 Pyramid 渲染器名称。为此,可以进行配置声明,以更改现有的 renderer factory 并添加新的渲染器工厂。

渲染器可以使用 pyramid.config.Configurator.add_renderer() 应用程序编程接口。

例如,添加渲染器以渲染具有 renderer 属性,该属性是以 .jinja2

config.add_renderer('.jinja2', 'mypackage.MyJinja2Renderer')

第一个参数是渲染器名称。第二个参数是对 renderer factory 或A dotted Python name 指这样一个物体。

添加新的渲染器

可以通过创建和注册 renderer factory .

渲染器工厂实现应符合 pyramid.interfaces.IRendererFactory 接口。它应该能够创建一个符合 pyramid.interfaces.IRenderer 接口。遵循此设置的典型类如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class RendererFactory:
    def __init__(self, info):
        """ Constructor: info will be an object having the
        following attributes: name (the renderer name), package
        (the package that was 'current' at the time the
        renderer was registered), type (the renderer type
        name), registry (the current application registry) and
        settings (the deployment settings dictionary). """

    def __call__(self, value, system):
        """ Call the renderer implementation with the value
        and the system value passed in as arguments and return
        the result (a bytes or string object).  The value is
        the return value of a view.  The system value is a
        dictionary containing available system values
        (e.g., view, context, and request). """

的形式化接口定义 info 传递给呈现器工厂构造函数的对象可用为 pyramid.interfaces.IRendererInfo .

基本上有两种不同类型的渲染器工厂:

  • 期望接受 asset specification 或绝对路径,如 name 的属性 info 对象被送入其构造函数。这些渲染器工厂在 name 以点开头的值 (. )这些类型的渲染器工厂通常与文件系统上的文件相关,例如模板。
  • 呈现器工厂,它希望接受不表示文件系统路径或中的资产规范的令牌。 name 的属性 info 对象被送入其构造函数。这些渲染器工厂在 name 不以点开头的值。这些渲染器工厂通常是对象序列化程序。

下面是一个注册简单渲染器工厂的示例,通过 add_renderer() 在哪里 config 是的实例 pyramid.config.Configurator()

config.add_renderer(name='amf', factory='my.package.MyAMFRenderer')

将上述代码添加到应用程序启动配置将允许您使用 my.package.MyAMFRenderer 视图配置中的渲染器工厂实现。应用程序可以通过指定 amfrenderer 的属性 view configuration

1
2
3
4
5
from pyramid.view import view_config

@view_config(renderer='amf')
def myview(request):
    return {'Hello':'world'}

在启动时,当 view configuration 遇到具有 name 不包含点的属性,完整 name 值用于从关联的渲染器工厂构造渲染器。在这种情况下,视图配置将创建 MyAMFRenderer 对于每个视图配置,包括 amf 作为其渲染器值。这个 name 传递给 MyAMFRenderer 构造函数将始终 amf .

下面是注册一个更复杂的渲染器工厂的示例,该工厂希望传递一个文件系统路径:

config.add_renderer(name='.jinja2', factory='my.package.MyJinja2Renderer')

将上述代码添加到应用程序启动将允许您使用 my.package.MyJinja2Renderer 在视图配置中通过引用 renderer 哪一个 结束于 .jinja2renderer 的属性 view configuration

1
2
3
4
5
from pyramid.view import view_config

@view_config(renderer='templates/mytemplate.jinja2')
def myview(request):
    return {'Hello':'world'}

当A view configuration 在启动时遇到具有 name 属性包含一个点,名称属性的值在其最后一个点上被拆分。拆分的第二个元素通常是文件扩展名。此扩展用于查找已配置视图的渲染器工厂。那么的价值 renderer 传递到工厂以为视图创建呈现器。在这种情况下,视图配置将创建 MyJinja2Renderer 对于每个视图配置,包括以 .jinja2 在其 renderer 价值。这个 name 传递给 MyJinja2Renderer 构造函数将是设置为 renderer= 在视图配置中。

添加默认渲染器

联想到 违约 渲染器 all 视图配置(即使是不具有 renderer 属性),通过 None 作为 name 渲染器标记的属性:

config.add_renderer(None, 'mypackage.json_renderer_factory')

更改现有渲染器

金字塔支持通过它的 Conflict Resolution 机制。这意味着,在大多数情况下,覆盖渲染器与使用 pyramid.config.Configurator.add_renderer() 方法重新定义模板扩展。例如,如果要重写 json 渲染器要指定新的渲染器,可以执行以下操作:

json_renderer = pyramid.renderers.JSON()
config.add_renderer('json', json_renderer)

执行此操作后,在 json 渲染器将使用新的渲染器。

在运行时重写渲染器

警告

这是一个高级功能,一般不由“平民”使用。

在某些情况下,有必要指示系统忽略开发人员在视图配置中提供的静态渲染器声明,将渲染器替换为另一个 请求开始后 . 例如,检测到请求来自XML-RPC客户端的“无所不在”XML-RPC实现可能会重写用户发出的视图配置语句,该语句指示视图将模板呈现器与使用XML-RPC呈现器的模板呈现器一起使用。此呈现器将生成可调用任意视图返回的数据的XML-RPC表示。

要使用此功能,请创建 NewRequest subscriber 它嗅探请求数据,并有条件地设置 override_renderer 请求本身的属性,依次是 name 注册的渲染器。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from pyramid.events import subscriber
from pyramid.events import NewRequest

@subscriber(NewRequest)
def set_xmlrpc_params(event):
    request = event.request
    if (request.content_type == 'text/xml'
            and request.method == 'POST'
            and not 'soapaction' in request.headers
            and not 'x-pyramid-avoid-xmlrpc' in request.headers):
        params, method = parse_xmlrpc_request(request)
        request.xmlrpc_params, request.xmlrpc_method = params, method
        request.is_xmlrpc = True
        request.override_renderer = 'xmlrpc'
        return True

如果请求似乎来自XML-RPC客户端,那么订阅服务器的结果将是用(概念上的,不存在的)XML-RPC呈现器替换开发人员配置的任何现有静态呈现器。