Python Pyramid 简明教程

Python Pyramid - Templates

默认情况下,视图函数的响应的内容类型为纯文本。为了呈现 HTML,响应主体文本可能包括 HTML 标签,如下例所示 −

Example

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response

def hello_world(request):
   return Response('<h1 style="text-align:center;">Hello World!</h1>')

if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('hello', '/')
      config.add_view(hello_world, route_name='hello')
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

Output

在启动服务器(通过运行以上代码)之后,访问 http://localhost:6543/ ,浏览器渲染以下输出 −

templates

但是,这种渲染 HTML 的方法,尤其是如果它可能包含某些可变数据,是极其繁琐的。出于此目的,Web 框架使用模板库。模板库将可变数据与其他静态 HTML 代码合并,以动态生成和呈现网页。

Template Bindings

Pyramid 提供了使用诸如 jinja2、Mako 和 Chameleon 等流行模板库的绑定来提供模板支持。

Template Language

Pyramid Bindings

Default Extensions

Chameleon

pyramid_chameleon

.pt, .txt

Jinja2

pyramid_jinja2

.jinja2

Mako

pyramid_mako

.mak, .mako

首先,我们需要为使用所需的模板库安装相应的 Python 库。例如,要使用 jinja2 模板,请使用 PIP 安装程序安装 pyramid_jinja2

pip3 install pyramid_jinja2

然后,我们需要将其包含在应用程序配置中。

config.include('pyramid_jinja2')

pyramid.renderers 模块定义了 render_to_response() 函数。它与以下参数一起使用 −

render_to_response(renderer_name, value, request)

renderer_name 是模板网页,通常保存在应用程序目录的子文件夹 templates 中,value 参数是作为上下文传递给模板的字典,以及从 WSGI 环境中获取的请求对象。

将以下 HTML 脚本另存为 hello.jinja2 目录中的 templates

<html>
   <body>
      <h1>Hello, {{ name }}!</h1>
   </body>
</html>

Jinja2 Template Library

这里,“name”是 jinja2 模板变量。jinja2 模板语言使用以下语法在 HTML 脚本中插入变量和编程构造:

Expressions

  1. {{ …​ }} 用作要打印到模板输出的表达式。

  2. {% …​ %} 用作语句。

  3. {# …​ #} 用作不包含在模板输出中的注释。

Conditionals

  1. {% if expr %}

  2. {% else %}

  3. {% endif %}

Loop

  1. {% for var in iterable %}

  2. {% endfor %}

在 {{ name }},上下文变量“name”的值在视图响应中动态呈现在 jinja2 中。

Rendering Template

hello_world() 视图函数通过调用 render_to_response() 函数直接呈现此模板。它还将上下文值发送到模板。

from pyramid.renderers import render_to_response

def hello_world(request):
   return render_to_response('templates/hello.jinja2',{'name':'Tutorialspoint'},
request=request)

Example

与往常一样,此视图被添加到 hello 路由,指向 / URL。完整的应用程序代码如下 −

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.renderers import render_to_response

def hello_world(request):
   return render_to_response('templates/hello.jinja2', {'name':'Tutorialspoint'}, request=request)

if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('hello', '/')
      config.include('pyramid_jinja2')
      config.add_view(hello_world, route_name='hello')
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

Output

运行服务器并访问 http://localhost:6543/ 。浏览器显示以下结果 −

hellotp

每个视图都返回一个响应对象。 render_to_response() 函数是一个快捷函数,实际上返回一个响应对象。这允许上面的 hello_world 视图直接返回其对 render_to_response() 的调用的结果。

另一方面, pyramid.renderers.render() 函数将模板渲染为字符串。我们可以直接生成一个响应对象,并使用该字符串作为响应的主体。

让我们按如下方式更改 hello_world() 视图函数 −

from pyramid.renderers import render

def hello_world(request):
   retval = render('templates/hello.jinja2',
   {'name':'Tutorialspoint'}, request=request)
   return Response(retval)

其余代码保持不变,浏览器也显示与上面相同的输出。

Rendering via Configuration

正如前面提到的,Pyramid 的视图可调用 id 返回的 HTTP 响应的 content_type 是 text/plain。但是,如果 @view_config 装饰器的 renderer 参数被分配了其中任何一个值,它可以被更改为字符串、JSON 或 JSONP。因此,Pyramid 具有以下内置渲染器 −

  1. JSON

  2. String

  3. JSONP

Example

在以下示例中,hello_world() 视图函数被配置为渲染 JSON 响应。

from pyramid.view import view_config

@view_config(route_name='hello',renderer='json')
def hello_world(request):
   return {'content':'Hello World!'}

Output

将 renderer 类型设置为 JSON 也将 HTTP 响应的 content_type 标头设置为 application/json 。浏览器显示 JSON 响应,如下图所示 −

json

@view_config() 装饰器的 renderer 参数可以设置为模板网页(它必须存在于 templates 文件夹中)。先决条件是模板库的适当 Python 绑定必须已安装,并且应用程序配置必须包括绑定。

我们已经安装了 python_jinja2 包,这样我们就可以使用 jinja2 模板由 hello_world() 视图函数渲染,该函数由带有 renderer 参数的 @view_config() 装饰。

hello.jinja2 模板 HTML 代码如下 −

<html>
   <body>
      <h1>Hello, {{ name }}!</h1>
   </body>
</html>

经过装饰的 hello_world() 函数被写为 −

from pyramid.view import view_config

@view_config(route_name='hello', renderer='templates/hello.jinja2')
def hello_world(request):
   return {'name':'Pyramid!'}

Example

在这种情况下,视图函数返回一个字典对象。它可作为上下文数据提供给模板,它可以在 HTML 文本中借助模板语言语法元素插入。

渲染 jinja2 模板的完整代码如下 −

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config

@view_config(route_name='hello', renderer='templates/hello.jinja2')
def hello_world(request):
   return {'name':'Pyramid!'}

if __name__ == '__main__':
   with Configurator() as config:
      config.include('pyramid_jinja2')
      config.add_route('hello', '/')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

Output

view 函数提供可变数据的模板网页如下所示 −

view

Add/Change Renderer

模板只不过是散布着模板语言语法的网页。尽管 Pyramid 使用 ".jinja2" 作为 jinja2 模板的默认扩展名,但惯例是使用 ".html" 扩展名作为网页。

我们可以更改应用程序配置以添加使用 ".html" 扩展名。这是通过 add_jinja2_renderer 完成的。

config.add_jinja2_renderer(".html")

hello.jinja2 模板现在被重命名为 hello.html。为了能够使用此模板,让我们将视图函数的定义更改为以下代码 −

from pyramid.view import view_config

@view_config(route_name='hello', renderer='templates/hello.html')
def hello_world(request):
   return {'name':'Pyramid!'}

同时,通过添加 ".html" 渲染器来修改 Configurator 对象的属性。

if __name__ == '__main__':
   with Configurator() as config:
      config.include('pyramid_jinja2')
      config.add_jinja2_renderer(".html")
      config.add_route(hello, '/')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

Template Context from matchdict

如前所述,如果路由配置中的 URL 模式包含一个或多个占位符参数,它们从请求 URL 中的值将与请求一起作为 matchdict 对象传递,而该对象反过来可以作为上下文数据传递给要渲染的模板。

对于我们的下一个示例, hello.html - Jinja2 模板保持不变。

<html>
   <body>
      <h1>Hello, {{ name }}!</h1>
   </body>
</html>

我们知道上下文变量 'name' 的值由视图函数传递。但是,我们并不是传递一个硬编码值(如前一个示例中所示),而是从 matchict 对象中获取它的值。此对象是由 URL 字符串中的路径参数填充的。

from pyramid.view import view_config

@view_config(route_name='index', renderer='templates/hello.html')
def index(request):
   return {'name':request.matchdict['name']}

Example

修改后的应用程序代码如下所示 −

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config

@view_config(route_name='index', renderer='templates/hello.html')
def index(request):
   return {'name':request.matchdict['name']}
if __name__ == '__main__':
   with Configurator() as config:
      config.include('pyramid_jinja2')
      config.add_jinja2_renderer(".html")
      config.add_route('index', '/{name}')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

Output

启动服务器,打开浏览器,输入 URL http://localhost:6543/Tutorialspoint 。结尾字符串成为 matchdict 中 'name' 键的值。它被 Jinja2 模板使用,并渲染出以下输出。

jinja2

Conditionals and Loops in Template

Jinja2 模板语言允许在 HTML 脚本中包含条件语句和循环构造。Jinja2 用于这些编程元素的语法如下所示 −

Conditionals

{% if expr %}
HTML
{% else %}
HTML
{% endif %}

Loop

{% for var in iterable %}
HTML
{% endfor %}

不难看出,Jinja2 语法与 Python 的 if 和 for 语句非常相似。不过,Jinja2 不使用缩进来标记块。相反,对于每个 if 都必须有一个 endif 语句。类似地,对于每个 for 语句,都必须有一个 endfor 语句。

Example

以下示例演示了模板条件和循环语句的使用。首先,Pyramid 代码使用一个 students 作为词典对象的列表,每个词典包含一个学生的 ID、姓名和百分比。此列表对象作为上下文传递给 marklist.html 模板

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config

students = [
   {"id": 1, "name": "Ravi", "percent": 75},
   {"id": 2, "name": "Mona", "percent": 80},
   {"id": 3, "name": "Mathews", "percent": 45},
]

@view_config(route_name='index', renderer='templates/marklist.html')

def index(request):
   return {'students':students}
if __name__ == '__main__':
   with Configurator() as config:
      config.include('pyramid_jinja2')
      config.add_jinja2_renderer(".html")
      config.add_route('index', '/')
      config.scan()
   app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

将此程序保存为 marklist.py。现在,必须将以下 HTML 脚本保存为 marklist.html。它遍历从视图函数接收的 students 列表对象,并将学生数据渲染为一个 HTML 表格。第四列使用 Jinja2 if 语句语法显示通过/失败结果。

<html>
<body>
   <table border=1>
      <thead>
         <tr>
            <th>Student ID</th> <th>Student Name</th>
            <th>percentage</th>
            <th>Result</th>
         </tr>
      </thead>
      <tbody>
         {% for Student in students %}
            <tr>
               <td>{{ Student.id }}</td>
               <td>{{ Student.name }</td>
               <td>{{ Student.percent }}</td>
               <td>
                  {% if Student.percent>=50 %}
                  Pass
                  {% else %}
                  Fail
                  {% endif %}
               </td>
            </tr>
         {% endfor %}
      </tbody>
   </table>
</body>
</html>

Output

运行 marklist.py 代码。 http://localhost:6543/ 链接渲染出以下表格结果 −

marklist