Pyramid和Chameleon中的Ajax小部件

3 投票
1 回答
1408 浏览
提问于 2025-04-17 05:56

我想要轻松创建一些基于ajax的“小部件”,这些小部件的后台是用chameleon和pyramid搭建的。

Pyramid有没有提供一些简单的代码,能让写这些小部件变得容易呢?

我现在的做法是有一个主页视图,它使用home.pt作为渲染器。home.pt使用一个叫base.pt的宏,这个宏定义了页面的结构,并为home.pt提供了一个可以填充的地方。base.pt还使用了我写的一个登录“小部件”宏(见下面的account_login_widget.pt)。

理论上,这听起来不错……我有一个可以在很多页面上重复使用的登录小部件,但我现在的做法效果不太好。我的登录小部件在渲染时使用了像${username}这样的变量(这些变量需要服务器来定义)。我希望登录小部件和它的渲染尽可能独立。但按照我现在的做法,主页视图的代码需要知道登录小部件的需求,并在字典中提供username、formrender和其他变量。这显然不好……

我觉得我离正确的想法很近,但还是缺少了一些东西……

有没有什么想法?

base.pt:

<html>
<head></head>
<body>
<div id="container">
    <div id="header">
        <span metal:use-macro="load: account_login_widget.pt"></span>     
    </div>
    <div id="middle">
        <span metal:define-slot="content"></span>
    </div>
    <div id="footer"></div>
</div>
</body>
</html>

home.pt:

<div metal:use-macro="load: base.pt">
<span metal:fill-slot="content">
    <div>my stuff</div>
</span>
</div>

account_login_widget.pt:

<span metal:define-macro="account_login_widget">
<script type="text/javascript">
(function($) {
    $.fn.my_function = function() {
        $('#login_form').submit(function(e) {
            e.preventDefault();

            // ajax call
            $.post(some_url, some_data, function(response) {
                $('#account_login_widget').html(response);
            });
        };
        return this;
    };
})(jQuery);

// Define the entry point    
$(document).ready(function() {
    $(document).my_function();
});
</script>

<div id="account_login_widget">
<div id="login_bar" tal:condition="not username">
    ${form_renderer.begin(...)}
        ... my form ...
    ${form_renderer.end()}
    <span tal:condition="login_failed">Login failed</span>
    <div id="forgot_password_link"><a href="#">Forgot Password?</a></div>
    <div id="create_account_link"><a href="${signup_url}">Create Account</a></div>
</div>
<div tal:condition="username">
    Welcome <strong>${username}</strong>! <a href="${logout_url}">Logout</a>
</div>
</div>
</span>

1 个回答

8

处理这个问题的一个好方法是把你的登录小部件(account_login_widget)和它自己的视图关联起来,像这样:

@view_config(name='login_widget',
             renderer='templates/account_login_widget.pt')
def login_widget(request):
    return {'username': ...}

这样你就可以访问 http://yourapp/login_widget,并只获取到小部件的HTML代码。

接下来你需要做的就是调用这个视图,并把得到的HTML放到你的模板里。也就是说,不要像这样:

<span metal:use-macro="load: account_login_widget.pt"></span>

你应该想要类似这样的:

<span tal:replace="structure render_view('login_widget')"></span>

render_view 这个在模板里是不存在的;你需要自己提供它。最好使用“渲染前事件”(Before Render Event)来实现这个功能:http://docs.pylonsproject.org/projects/pyramid/dev/narr/hooks.html#beforerender-event

from pyramid.events import subscriber
from pyramid.events import BeforeRender
from pyramid.view import render_view_to_response

@subscriber(BeforeRender)
def add_render_view_global(event):
    event['render_view'] = lambda name: render_view_to_response(context, request, name, secure).ubody

完成了。这种方法也会在你需要通过AJAX动态加载小部件时提供帮助。

撰写回答