Ajax виджеты в пирамиде и хамелеоне
Я хотел бы иметь возможность легко создавать ajax-виджеты, поддерживаемые хамелеоном и пирамидой на стороне сервера.
Предоставляет ли Pyramid какой-либо программный код, облегчающий написание виджетов?
Мой текущий подход заключается в том, что у меня есть домашний вид, который использует home.pt в качестве средства визуализации. home.pt использует макрос base.pt, который определяет структуру страницы и предоставляет место для заполнения home.pt. base.pt также использует макрос входа в систему 'widget', который я написал (см. account_login_widget.pt ниже).
В теории все это звучит великолепно... У меня есть многоразовый виджет входа в систему, который я могу использовать на многих страницах, но мой нынешний подход работает не очень хорошо. Мой виджет входа в систему использует переменные типа ${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
однако не существует в шаблонах; Вы должны будете предоставить это самостоятельно. Для этого лучше всего использовать событие "Перед рендерингом": http://docs.pylonsproject.org/projects/pyramid/dev/narr/hooks.html
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.