виджеты ajax в пирамиде и хамелеоне

Я хотел бы иметь возможность легко создавать «виджеты» ajax, поддерживаемые хамелеоном и пирамидой на стороне сервера.

Предоставляет ли Pyramid какой-либо программный код, облегчающий написание виджетов?

Мой текущий подход заключается в том, что у меня есть домашний вид, который использует home.pt в качестве средства визуализации. home.pt использует макрос base.pt, который определяет структуру страницы и предоставляет слот для заполнения home.pt. base.pt также использует макрос «виджета» входа, который я написал (см.: account_login_widget.pt ниже).

Теоретически все это звучит великолепно... У меня есть многоразовый виджет входа в систему, который я могу использовать на многих страницах, но мой текущий подход работает не очень хорошо. Мой виджет входа в систему использует такие переменные, как ${username} в своем рендерере (который должен определить сервер). Я хочу, чтобы виджет входа в систему и его рендеринг были максимально независимыми. Но с моим нынешним способом ведения дел код домашнего просмотра должен знать о потребностях виджета входа и предоставлять имя пользователя, форму и другие переменные в словаре. Однозначно не хорошо...

Я чувствую, что я близок к правильной идее, но упускаю некоторые вещи...

Есть предположения?

база.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>

дом.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>

person lostdorje    schedule 09.11.2011    source источник
comment
Я должен упомянуть, что в настоящее время я думаю о том, чтобы иметь класс BaseView, который будет расширять все мои представления. В этом классе BaseView у меня может быть метод add Widget, который возьмет мой объект представления виджета и добавит все его переменные зависимости в dict, который в конечном итоге вернет мое представление.   -  person lostdorje    schedule 09.11.2011


Ответы (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#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.

person Daniel Nouri    schedule 09.11.2011
comment
Спасибо! Эта стратегия звучит довольно хорошо и помогает мне далеко продвинуться. Однако есть еще один или два излома. Ваше предложение предполагает использование обхода? Я использую отправку URL. У меня проблема в том, что @view_config не указывает route_name, поэтому URL-адрес: yourapp/login_widget не является найдено (это также означает, что мой пост ajax не работает). Но когда я указываю route_name в дополнение к имени, вызов render_view_to_response() не преобразуется в представление. Кажется, я могу указать только «имя» или «имя_маршрута» в «@view_config», но не оба. Что здесь не так? - person lostdorje; 09.11.2011
comment
Добавление двух view_configs помогает. Комбинированные предикаты были слишком конкретными. Но добавление 2 view_configs тоже кажется неудобным. @view_config(name='account_login_widget', renderer='template/account_login_widget.pt') @view_config(route_name='account_login_widget', renderer='template/account_login_widget.pt') - person lostdorje; 09.11.2011
comment
Ты прав. Бит конфигурации представления моего ответа (@view_config) предполагает обход. Конфигурация представления будет отличаться, если вы используете диспетчеризацию URL-адресов. docs.pylonsproject.org/projects/pyramid/dev/ рассказ/ - person Daniel Nouri; 10.11.2011