Python Pyramid - 模板

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


示例

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()

输出

启动服务器后(通过运行上面的代码),访问http://localhost:6543/,浏览器呈现如下输出 −

模板

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


模板绑定

Pyramid 借助绑定到流行的模板库(如 jinja2、Mako 和 Chameleon)来提供模板支持。

模板语言 Pyramid 绑定 默认扩展
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.jinja2templates 文件夹中。

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

Jinja2 模板库

这里,'name' 是一个 jinja2 模板变量。 jinja2 模板语言使用以下语法在 HTML 脚本中插入变量和编程结构 −

表达式

  • {{ ... }} 用于打印到模板输出的表达式。

  • {% ... %} 用于语句。

  • {# ... #} 用于未包含在模板输出中的注释。

条件

  • {% if expr %}

  • {% else %}

  • {% endif %}

循环

  • {% for var in iterable %}

  • {% endfor %}

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


渲染模板

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)

示例

像往常一样,这个视图被添加到 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()

输出

运行服务器并访问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)

其余代码相同,浏览器也显示与上述相同的输出。


通过配置渲染

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

  • JSON

  • String

  • JSONP

示例

在下面的示例中,hello_world() 视图函数被配置为呈现 JSON 响应。

from pyramid.view import view_config

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

输出

将渲染器类型设置为 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!'}

示例

在这种情况下,视图函数返回一个字典对象。 它作为上下文数据提供给模板,可以借助模板语言语法元素将其插入 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()

输出

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

视图

添加/更改渲染器

模板只不过是穿插有模板语言语法的网页。 尽管 Pyramid 使用 jinja2 模板的默认扩展名".jinja2",但惯例是使用网页的".html"扩展名。

我们可以更改应用程序配置,让除了".jinja2"之外还可以使用.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()

来自 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']}

示例

修改后的应用代码如下 −

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()

输出

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

Jinja2

模板中的条件语句和循环结构

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 语句。

示例

以下示例演示了模板条件和循环语句的使用。 首先,金字塔代码使用一个学生作为字典对象列表,每个字典都有一个学生的 ID、 name 和 percentage。 此列表对象作为上下文传递给 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。 它遍历从视图函数接收到的学生列表对象,并以 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>

输出

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

Marklist