Pyramid和Chameleon中的Ajax小部件
我想要轻松创建一些基于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 个回答
处理这个问题的一个好方法是把你的登录小部件(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动态加载小部件时提供帮助。