有没有更好的方法在Pyramid中切换HTML和JSON输出?

时间:2011-01-08 09:54:11

标签: python api pylons pyramid

# /test{.format} no longer seems to work...
config.add_route('test', '/test.{ext}', view='ms.views.test')

views.py:

from pyramid.response import Response
from pyramid.renderers import render

import json

def test(request):
    extension = request.matchdict['ext']
    variables = {'name' : 'blah', 'asd' : 'sdf'}

    if extension == 'html':
        output = render('mypackage:templates/blah.pt', variables, request=request)

    if extension == 'json':
        output = json.dumps(variables)

    return Response(output)

有更简单的方法吗?有了Pylons,这很简单:

def test(self, format='html'):
    c.variables = {'a' : '1', 'b' : '2'}

    if format == 'json':
        return json.dumps(c.variables)

    return render('/templates/blah.html')

我怀疑我接近这个错误的方式......?

4 个答案:

答案 0 :(得分:51)

我认为,更好的方法是使用差异渲染器两次添加相同的视图。假设我们有以下观点:

def my_view(request):
    return {"message": "Hello, world!"}

现在在我们的配置中,我们可以添加两次相同的视图:

from pyramid.config import Configurator
config = Configurator()
config.add_route('test', '/test', my_view, renderer="templates/my_template.mako")
config.add_route('test', '/test', my_view, renderer="json", xhr=True)

我们现在拥有的:

  1. 如果我们将浏览器指向网址my_view,则视图"templates/my_template.mako"将呈现模板/test,其中返回的字典作为上下文提供。
  2. 如果我们将再次调用带有my_view的XHR请求,但现在返回dict将被编码为JSON并传回给调用者(请read docs关于检查请求是否通过XHR完成)
  3. 我们可以使用相同的想法来定义不同的路线,但附加相同的视图:

    from pyramid.config import Configurator
    config = Configurator()
    config.add_route('test', '/test', my_view, renderer="templates/my_template.mako")
    config.add_route('test_json', '/test.json', my_view, renderer="json")
    

    现在/test将触发模板呈现,但/test.json将仅返回JSON编码的字符串。

    您可以通过accept方法的add_router参数进一步调度到正确的渲染器:

    from pyramid.config import Configurator
    config = Configurator()
    config.add_route('test', '/test', my_view, renderer="templates/my_template.mako")
    config.add_route('test', '/test', my_view, renderer="json", accept="application/json")
    

    如果请求标头Accept设置为application/json,则会返回JSON,否则您将获得渲染模板。

    请注意,只有在您想要对视图中的响应进行编码的预定义数据格式集时,这才有效,但这是常见的情况。如果您需要动态调度,可以使用decorate add_route参数来装饰您的视图,该参数将根据您的规则选择正确的渲染器。

答案 1 :(得分:6)

这是你要找的吗? Pylons和Pyramid有不同的API。所以他们会有所不同。你可以使它们更相似,但你不能使它们相同。

def test(request):
    extension = request.matchdict['ext']
    variables = {'name' : 'blah', 'asd' : 'sdf'}

    if extension == 'json':
        return Response( json.dumps(variables) )

    return Response( render('mypackage:templates/blah.pt', variables, request=request) )

答案 2 :(得分:2)

PyramidURL Dispatch是非常强大而灵活的机制。首先,我们将编写正确的url模式。在route pattern syntax中,我们可以使用regular expressions替换标记。

'/test{ext:\\..*}'

在这里我们可以看到url路径应该包含。 (期间)然后是任何符号。所有符号包括。 (句点)将位于ext中的request.matchdict键下。

当然,我们可以使正则表达式复杂化,以指定可能的扩展名:

'/test{ext:\\.(html|json)}'

然后我们使用我们的模式添加路线:

config.add_route('test',
                 pattern='/test{ext:\\.(html|json)}')

想要添加,我们可以使用custom predicates指定扩展程序集。

为了指定默认扩展名,我们可以使用简单的pregenerator

def default_extension(ext):
    def pregenerator(request, elements, kw):
        if 'ext' not in kw:
            kw['ext'] = ext

        return elements, kw

    return pregenerator

config.add_route('test',
                 pattern='/test{ext:\\.(html|json)}',
                 pregenerator=default_extension('.html'))

request.route_path('test')
# '/test.html'
request.route_path('test', ext='.json')
# '/test.json'

之后我们将Traversal帮助我们在 html json 输出之间切换:

config.add_route('test',
                 '/test{ext:\\.(html|json)}',
                 pregenerator=default_extension('.html'),
                 traverse='{ext}')

使用traverse中的add_route参数,我们强制我们的应用程序为 hybrid 。我们应该理解为我们的视图提供上下文的工厂不得包含与我们的扩展匹配的键。 默认根工厂没有。

views.py:

from pyramid.view import view_config, view_defaults


@view_defaults(route_name='test')
class Test(object):
    def __init__(self, request):
        self.request = request
        self.variables = {
            'name': 'blah',
            'asd': 'sdf'
        }

    @view_config(name='.html', renderer='mypackage:templates/blah.pt')
    def html(request):
        return {
            'request': request,
            'variables': self.variables
        }

    @view_config(name='.json', renderer='json')
    def json(request):
        return {
            'request': request,
            'variables': self.variables
        }

这里我们创建了class Test并为其指定了路由名称。然后我们按扩展名称分隔方法。

答案 3 :(得分:0)

尝试这种方式:

def test(self, format='html'):
    c.variables = {'a' : '1', 'b' : '2'}

    if format == 'json':
        return Response(json = c.variables)

    return render_to_response('/templates/blah.html')

这与您的挂架示例最相似。它还显示了一些更友好的方式来呈现模板或一些JSON到响应。