访问子模板中声明的变量或全局控制器变量

4 投票
4 回答
1343 浏览
提问于 2025-04-16 15:06

我有一组小的mako模板,结构大致是这样的:

base.mako

<h1>${self.view()}</h1>
${listactions(self.mainactions)}
${self.body()}

<%def name="listactions(actions)">
    <ul>
    % for action in actions:
        <li>${action}</li>
    % endfor
    </ul>
</%def>

clientsbase.mako

<%inherit file="base.mako"/>
<%def name="view()">Clients</%def>
<%
    mainactions = [request.route_url('clientsnew')]
%>

clientsindex.mako

<%inherit file="clientsbase.mako"/>
This is the index

问题是,当我尝试访问显示clientsindex.mako的客户索引视图时,我遇到了一个错误:AttributeError: Namespace 'self:/base.mako' has no member 'mainactions'

那么,正确的做法应该是什么呢?我查阅了mako的文档,发现我可以使用一个模块级的python块来声明mainactions,然后在base.mako中使用self.attr.mainactions。但问题是,在这个块里我无法访问请求对象。

我想再问一个问题:在我的情况下,我使用函数作为视图调用,但假设我写了一个单独的clients.py视图文件,里面包含所有与客户相关的视图。有没有办法从clients.py文件中设置一些类似于控制器范围的上下文变量?这样我就可以在模板的上下文中提前设置一个mainactions变量,而不需要在每个视图的字典中返回它。

4 个回答

0

这个回答有点老了,所以我不知道你是否已经解决了这个问题。

一种可能有效的方法是把你的 Python 代码块放在 view() 函数里面。这样的话,那个变量就能在 base.mako 中被调用了。

在我自己的应用中,我创建了一个 view 对象,用来存放我在整个应用中需要的一些上下文变量,比如 view.page、view.perpage 等等。在每次调用视图的时候,我都会初始化这个 view(自动从请求、提交的数据、路由等中计算出上下文变量),然后把它作为上下文变量传递出去。因此,你总是可以传递 view.mainactions,只要默认保持它为 None,你就不会在应用中遇到 KeyErrors 的问题。

0

嗯……我已经很久没用pylons写东西了,也没有安装pylons来检查这个问题。不过你可以试着把 self.mainactions 改成 next.mainactions,看看会发生什么。

1

这是个比较老的问题,但我觉得这里的解释可能会有帮助。记住,当你写模板的时候,默认情况下其实是在显示一个叫 body() 的函数。

我猜 mainactions 是作为 self.body() 的一个局部变量被定义的。不过没关系,因为我们可以访问到 self……

所以,不要写:

mainactions = [request.route_url('clientsnew')]

你应该试着写:

self.mainactions = [request.route_url('clientsnew')]

不过,这样做其实并不是实现你想要的功能的好方法。如果我是你,我会用 defblock 来做。

base.mako 中:

<h1>${self.view()}</h1>
<%block name="mainaction">
</%block>
${self.body()}

<%def name="listactions(actions)">
    <ul>
    % for action in actions:
        <li>${action}</li>
    % endfor
    </ul>
</%def>

clientbase.mako 中:

<%inherit file="base.mako"/>
<%def name="view()">Clients</%def>
<%block name="mainaction"
    ${request.route_url('clientsnew')}
</%block>

其他的部分没有变化……使用 def 的好处在于你可以覆盖父类中的 def,然后在 base.mako 中使用你想要的 def

就这些了。

撰写回答