Pyramid中更好的Ajax加载模式?

4 投票
2 回答
2640 浏览
提问于 2025-04-17 08:48

我看过关于使用不同的渲染器重写渲染器的内容,但我在想有没有更好的方法来处理这种情况。

现在,在我的视图中,我把一组项目返回给模板:

@view_config(
    route_name = 'name',
    permission = 'perm',
    renderer   = 'r.mako'
)
def r( request ):
     items = get_items()
     return { 'items': items }

现在我想让ajax版本只渲染其中的一部分,同时还带上一些数据。我的当前代码是:

@view_config(
    route_name = 'name',
    permission = 'perm',
    renderer   = 'r.mako'
)
def r( request ):
     items = get_items()

     if ajax:
         return Response( to_json( {
                             'data1':  1,
                             'data2':  2,
                             'data3':  3,
                             'html':  renderers.render( 'shortr.mako',
                                                        { 'items': items },
                                                        request )
                         } )

     return { 'items': items }

我具体想知道有没有更简单的方法来重写渲染器,然后再把它包裹在某个东西里,而不需要明确调用渲染,也不必确保字典或请求作为参数是正确的。谢谢!

2 个回答

1

我对pyramid不太熟悉,也不知道'r.mako'指的是什么,但你可以在控制器被调用之前,使用一个自定义函数来处理请求。这种函数可以检查请求中的Accepts头,看里面是否有'text/javascript'或'application/json'这些内容,如果有,就在请求对象上设置一个标记(或者把这个方法单独提取出来,以便在你的r函数中使用)。

然后,你可以做一个自定义的渲染器,来处理用mako解析数据或者生成一个json字符串。

# pseudo-code
def before_controller(request, response):
    if 'text/html' in request.headers.accepts:
        request.is_json = False
    elif 'application/json' in request.headers.accepts:
        response.headers.set('Content-type', 'application/json')
        request.is_json = True

# pseudo-code
def my_renderer(request, response, result):
    if 'text/html' in request.headers.accepts:
        return # render html
    elif 'application/json' in request.headers.accepts:
        response.headers.set('Content-type', 'application/json')
        return json.dumps(result)

#
def r(request):
    items = get_items()
    if request.json:
        pass # update items with additional data
    return {'items': items} # one point of return

这样做的话,如果你不需要对数据进行额外处理,就不需要多花时间,你只需正常返回结果,另一端就能收到json对象。

如果你无法在控制器被调用之前接入pyramid,你可以写一个方便的函数来调用is_json(request),然后在控制器和渲染器中使用这个函数,以确定输出格式并设置内容类型的头信息。

8

我建议使用两个视图,这样可以让你对同一份数据应用不同的“外观和感觉”(响应)。

def get_items(request):
    return {} # values that you can pick and choose from in each view

@view_config(route_name='name', permission='perm', xhr=True, renderer='json')
def r_ajax(request):
    items = get_items(request)
    return {
        'data1': 1, 'data2': 2, 'data3': 3,
        'html': renderers.render('shortr.mako', {'items': items}, request),
    }

@view_config(route_name='name', permission='perm', renderer='r.mako')
def r_html(request):
    items = get_items(request)
    return items

如果你担心在视图配置中重复一些内容,Pyramid 1.3 版本带来了一个很不错的新功能,专门针对基于类的视图:

@view_defaults(route_name='name', permission='perm')
class R(object):
    def __init__(self, request):
        self.request = request
        self.items = # ...

    @view_config(xhr=True, renderer='json')
    def ajax(request):
        return {
            'data1': 1, 'data2': 2, 'data3': 3,
            'html': renderers.render('shortr.mako', {'items': items}, request),
        }

    @view_config(renderer='r.mako')
    def html(request):
        return self.items

撰写回答