Question

I'd like to do something like below.

I have the following routes configured:

config.add_route('home', '/')
config.add_route('foo', '/foo')

The following views:

@view_config(route_name='home', renderer='templates/home.pt')
def home_view(request):
    return {...}

@view_config(route_name='foo', renderer='templates/foo.pt')
def foo_view(request):
    return {...}

There is a base template 'templates/base.pt':

<!DOCTYPE html>
<html>
<head></head>
<body>
    Welcome ${user_id}<br>
    <a href="/foo">Foo</a><br>
    <div id="content">
        <!-- Inject rendered content here from either / or /foo --> 
    </div>
</body>
</html>

Now in my views I'd like to inject the following content into the div with id "content":

<!-- templates/home.pt -->
<div id="home-content">Home content</div>

<!-- templates/foo.pt -->
<div id="foo-content">Foo content</div>

How would I go about changing home_view and foo_view above so that they can inject their own templates (home.pt, foo.pt) into base.pt? Somehow I also need to transfer data such as ${user_id} into base.pt as well. I was playing around with the wrapper argument when defining my views, but couldn't figure out how it works.

Was it helpful?

Solution

You can achieve this in several ways (see e.g. Using ZPT Macros in Pyramid or Chameleon documentation introduction).

In your simple case, I think this is the fastest way: first, change your base.pt file to:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:tal="http://xml.zope.org/namespaces/tal"
      xmlns:metal="http://xml.zope.org/namespaces/metal">
<head></head>
<body>
    Welcome ${user_id}<br>
    <a href="/foo">Foo</a><br>
    <div id="content">
        <tal:block metal:define-slot="content">
        </tal:block>
    </div>
</body>
</html>

This defines a content slot of the Chameleon macro.

Your foo.pt could look like this:

<metal:main
    xmlns:tal="http://xml.zope.org/namespaces/tal"
    xmlns:metal="http://xml.zope.org/namespaces/metal"
    use-macro="load: base.pt">
    <tal:block metal:fill-slot="content">
        <div id="foo-content">Foo content</div>
    </tal:block>
</metal:main>

Note the use-macro="load: base.pt line. home.pt should follow the same pattern. user_id and other template variables are available to the macro, so, for example, if you set user_id to USER, /foo will render:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head></head>
<body>
    Welcome USER<br>
    <a href="/foo">Foo</a><br>
    <div id="content">
        <div id="foo-content">Foo content</div>
    </div>
</body>
</html>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top