1: Template Layout Preparation¶
Get a Twitter Bootstrap-themed set of Jinja2 templates in place.
Background¶
In this traversal tutorial, we'll have a number of views and templates, each with some styling and layout. Let's work efficiently and produce decent visual appeal by getting some views and Jinja2 templates with our basic layout.
Objectives¶
Get a basic Pyramid project in place with views and templates based on
pyramid_jinja2
.Have a "layout" master template and some included subtemplates.
Steps¶
Let's start with an empty hierarchy of directories. Starting in a tutorial workspace (e.g.,
quick_traversal
):$ mkdir -p layout/tutorial/templates $ cd layout
Make a
layout/setup.py
:1from setuptools import setup 2 3requires = [ 4 'pyramid', 5 'pyramid_jinja2', 6 'pyramid_debugtoolbar' 7] 8 9setup(name='tutorial', 10 install_requires=requires, 11 entry_points="""\ 12 [paste.app_factory] 13 main = tutorial:main 14 """, 15)
You can now install the project in development mode:
$ $VENV/bin/python setup.py develop
We need a configuration file at
layout/development.ini
:1[app:main] 2use = egg:tutorial 3pyramid.reload_templates = true 4pyramid.includes = 5 pyramid_debugtoolbar 6 7[server:main] 8use = egg:pyramid#wsgiref 9host = 0.0.0.0 10port = 6543 11 12# Begin logging configuration 13 14[loggers] 15keys = root, tutorial 16 17[logger_tutorial] 18level = DEBUG 19handlers = 20qualname = tutorial 21 22[handlers] 23keys = console 24 25[formatters] 26keys = generic 27 28[logger_root] 29level = INFO 30handlers = console 31 32[handler_console] 33class = StreamHandler 34args = (sys.stderr,) 35level = NOTSET 36formatter = generic 37 38[formatter_generic] 39format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s 40 41# End logging configuration
In
layout/tutorial/__init__.py
wire uppyramid_jinja2
and scan for views:1from pyramid.config import Configurator 2 3 4def main(global_config, **settings): 5 config = Configurator(settings=settings) 6 config.include('pyramid_jinja2') 7 config.scan('.views') 8 return config.make_wsgi_app()
Our views in
layout/tutorial/views.py
just has a single view that will answer an incoming request for/hello
:1from pyramid.view import view_config 2 3 4class TutorialViews(object): 5 def __init__(self, request): 6 self.request = request 7 8 @view_config(name='hello', renderer='templates/site.jinja2') 9 def site(self): 10 page_title = 'Quick Tutorial: Site View' 11 return dict(page_title=page_title)
The view's renderer points to a template at
layout/tutorial/templates/site.jinja2
:1{% extends "templates/layout.jinja2" %} 2{% block content %} 3 4<p>Welcome to the site.</p> 5 6{% endblock content %}
That template asks to use a master "layout" template at
layout/tutorial/templates/layout.jinja2
:1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <title>{{ page_title }}</title> 5 <link rel="stylesheet" 6 href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css"> 7</head> 8<body> 9 10<div class="navbar navbar-inverse"> 11 <div class="container"> 12 {% include "templates/header.jinja2" %} 13 </div> 14</div> 15 16<div class="container"> 17 18 <div> 19 {% include "templates/breadcrumbs.jinja2" %} 20 </div> 21 22 <h1>{{ page_title }}</h1> 23 {% block content %} 24 {% endblock content %} 25 26</div> 27 28</body> 29</html>
The layout includes a header at
layout/tutorial/templates/header.jinja2
:1<a class="navbar-brand" 2 href="{{ request.resource_url(request.root) }}">Tutorial</a>
The layout also includes a subtemplate for breadcrumbs at
layout/tutorial/templates/breadcrumbs.jinja2
:1<span> 2 <a href="#">Home</a> >> 3</span>
Simplified tests in
layout/tutorial/tests.py
:1import unittest 2 3from pyramid.testing import DummyRequest 4 5 6class TutorialViewsUnitTests(unittest.TestCase): 7 def _makeOne(self, request): 8 from .views import TutorialViews 9 inst = TutorialViews(request) 10 return inst 11 12 def test_site_view(self): 13 request = DummyRequest() 14 inst = self._makeOne(request) 15 result = inst.site() 16 self.assertIn('Site View', result['page_title']) 17 18 19class TutorialFunctionalTests(unittest.TestCase): 20 def setUp(self): 21 from tutorial import main 22 app = main({}) 23 from webtest import TestApp 24 self.testapp = TestApp(app) 25 26 def test_it(self): 27 result = self.testapp.get('/hello', status=200) 28 self.assertIn(b'Site View', result.body)
Now run the tests:
1$ $VENV/bin/nosetests tutorial 2. 3---------------------------------------------------------------------- 4Ran 2 tests in 0.141s 5 6OK
Run your Pyramid application with:
$ $VENV/bin/pserve development.ini --reload
Open
http://localhost:6543/hello
in your browser.
Analysis¶
The @view_config
uses a new attribute: name='hello'
. This, as we'll see
in this traversal tutorial, makes a hello
location available in URLs.
The view's renderer uses Jinja2's mechanism for pointing at a master layout and filling certain areas from the view templates. The layout provides a basic HTML layout and points at Twitter Bootstrap CSS on a content delivery network for styling.