简体   繁体   中英

access variable declared in child template or controller-wide variables

I have a small hierarchy of mako templates that go something like:

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

The problem is when I try to access the clients index view which renders clientsindex.mako I get the error AttributeError: Namespace 'self:/base.mako' has no member 'mainactions' .

What should be the proper way to do this? I've gone through the mako documentation and what I've found so far is I can use a module-level python block to declare mainactions and then in base.mako just do self.attr.mainactions . The problem with that is inside this block I don't have access to the request object.

I guess another question would be: in my case I'm using functions as view-callables, but let's say I've written a seperate clients.py view file which holds all the views related to clients. Is there a way to set sort of like controller-wide context variables from the clients.py file somehow? This way I could have a mainactions variable set in the template's context already without returning it in each view's dict.

It's a quite old question but here, I guess it might do the trick. Keep in mind that when you're writing a template, you're actually displaying by default the function body() .

My guess is that mainactions is being defined as a local variable for the self.body() . But everything is cool since we do have access to self...

so instead of writing:

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

You should try writing:

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

That said, this is not really a good way to achieve what you wanted to do. If I were you, i'd do it using def or block .

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>

The remaining doesn't change...the thing with def is that you just overide the def from parent and then in the base.mako you use the def where you want.

That's pretty much it.

This answer is to your 'other question' :)

You can define your views as methods on a Controller class. This way you can factor the Controller-wide variable output into a common method:

from pyramid.view import view_config
from myproject.resources import MyResource


class MyController(object):

    def __init__(self, request):
        self.request = request

    def respond(self, additionalVars):
        additionalVars['myCommonVar1'] = 'common value'
        return additionalVars

    @view_config(
        context='myproject.resources:MyResource',
        request_method='GET',
        renderer='one.mak')
    def get_one(self):
        return self.respond({'var2':'sth'})

    @view_config(
        context='myproject.resources:MyResource',
        name = 'two',
        request_method='GET',
        renderer='two.mak')
    def get_two(self):
        return self.respond({'var3':'sth else'})

Hmmm... I have not written anything in pylons for ages nor do I have any pylons installation to check it. But please try to write next.mainactions instead of self.mainactions and see what happens.

this answer is old, so I don't know if you already solved this problem.

One way that might work is moving your python block within the view() def. That way that variable will actually be called in base.mako.

In my own app, I created a view object that holds a bunch of contextual variables that I need throughout my app, for example view.page, view.perpage, etc. On every view callable, I initiate this view (calculate contextual variables from gets, post_data, routes, etc. automatically) and pass it as a context variable. Thus, you can always pass view.mainactions, and you won't run into any KeyErrors in your app as long as you keep it None by default.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM