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

发布于 2024-10-11 10:28:23 字数 859 浏览 4 评论 0原文

# /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')

我怀疑我以错误的方式处理这个问题......?

# /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)

Is there an easier way to do this? With Pylons, it was a simple:

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

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

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

I suspect I'm approaching this the wrong way...?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

帥小哥 2024-10-18 10:28:23

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

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"如果我们将浏览器指向 url /test,则返回的字典将作为上下文提供。
  2. 如果我们使用 my_view 发出 XHR 请求,将再次调用,但现在返回的 dict 将被编码为 JSON 并传输回调用者(请 阅读有关检查请求是否通过 XHR 完成的文档)。

我们可以使用相同的想法来定义不同的路由,但附加相同的视图:

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编码的字符串。

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

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 将被返回,否则你会得到渲染的模板。

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

I think, the better way is to add the same view twice with difference renderers. Suppose we have the following view:

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

Now in our configuration we can add the same view twice:

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)

What we have now:

  1. View my_view will render template "templates/my_template.mako" with returned dict provided as context if we will point our browser to url /test.
  2. If we will make XHR request with my_view will be called again, but now returned dict will be encoded as JSON and transmitted back to caller (please read docs about checking if request was done via XHR).

The same idea we can use for defining different routes but with the same view attached to them:

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")

Now /test will trigger template rendering, but /test.json will return just JSON encoded string.

You can go further and make dispatching to the right renderer via accept argument of add_router method:

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")

If request comes with header Accept set to application/json value JSON will be returned, otherwise you got rendered template.

Note, this will work only if you have predefined set of data formats in which you want to encode responses from your views, but it's the usual case. In case you need dynamical dispatching you can decorate your views with decorate argument of add_route which will choose the right renderer with your rules.

一绘本一梦想 2024-10-18 10:28:23

这是您要找的吗? 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) )

Is this what you're looking for? Pylons and Pyramid have different API's. So they will be different. You can make them a little more similar, but you can't make them identical.

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) )
紫竹語嫣☆ 2024-10-18 10:28:23

金字塔URL Dispatch 是非常强大和灵活的机制。首先,我们将编写正确的 url 模式。在路由模式语法中,我们可以使用正则表达式作为替换标记。

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

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

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

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

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

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

要补充的是,我们可以使用 自定义谓词

为了指定默认扩展,我们可以使用简单的 预生成器

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'

之后我们将遍历来帮助我们在htmljson 输出:

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

通过 add_route 中的 traverse 参数,我们强制我们的应用程序成为混合。我们应该明白,为我们的视图提供上下文的工厂不得包含与我们的扩展匹配的键。 默认根工厂没有。

视图.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 并为其指定了路由名称。然后我们通过扩展名来分隔方法。

Pyramid's URL Dispatch is very powerful and flexible mechanism. First of all, we'll write correct url pattern. In route pattern syntax we can use regular expressions for replacement markers.

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

Here we can see that url path should contain . (period) and then any symbols. All symbols including . (period) will be under the key ext in request.matchdict.

Of course, we can complicate the regular expression in order to specify what extensions there may be:

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

Then we adding route with our pattern:

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

Want to add, that we can specify the set of extensions using custom predicates.

In order to specify the default extension we can use simple 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'

After that we'll Traversal to help us switch between html and json output:

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

With the traverse argument in add_route we force our application to be hybrid. And we should understand that the factory which will provide context for our views must not contain the keys matching our extensions. The default root factory doesn't.

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
        }

Here we've created class Test and specify route name for it. And then we've separated methods by names of our extensions.

泛滥成性 2024-10-18 10:28:23

尝试这种方式:

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 到响应。

Try this way:

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')

This is the most similar to your pylons example. Also it shows some more friendly way to render a template or some JSON to a response.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文