Python Pyramid 简明教程

Python Pyramid - Templates

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

By default, the content-type of the response of a view function is in plain text. In order to render HTML, the text of the response body may include HTML tags, as in the following example −

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/ ,浏览器渲染以下输出 −

After starting the server (by running the above code), visit to http://localhost:6543/, the browser renders following output −

templates

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

However, this method of rendering HTML, especially if it is likely to contain certain variable data, is extremely cumbersome. For this purpose, web frameworks use templating libraries. A template library merges the variable data with the otherwise static HTML code to generate and render web pages dynamically.

Template Bindings

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

Pyramid provides templating support with the help of bindings to popular template libraries such as jinja2, Mako and 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

First of all, we need to install the corresponding Python library for using the required template library. For example, to use jinja2 template, install pyramid_jinja2 using PIP installer.

pip3 install pyramid_jinja2

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

Then we need to include it in the application configuration.

config.include('pyramid_jinja2')

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

The pyramid.renderers module defines render_to_response() function. It is used with following parameters −

render_to_response(renderer_name, value, request)

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

The renderer_name is the template web page, usually saved in the templates subfolder of the application directory, the value parameter is a dictionary passed as a context to the template, and the request object obtained from WSGI environment.

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

Save the following HTML script as hello.jinja2 in the templates folder.

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

Jinja2 Template Library

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

Here, 'name' is a jinja2 template variable. The jinja2 template language inserts variables and programming constructs in the HTML scripts using following syntax −

Expressions

  1. {{ …​ }} for Expressions to print to the template output.

  2. {% …​ %} for Statements.

  3. {# …​ #} for Comments not included in the template output.

Conditionals

  1. {% if expr %}

  2. {% else %}

  3. {% endif %}

Loop

  1. {% for var in iterable %}

  2. {% endfor %}

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

In hello.jinja2 {{ name }}, the value of 'name' context variable is dynamically rendered in the view response.

Rendering Template

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

The hello_world() view function directly renders this template by calling render_to_response() function. It also sends a context value to the template.

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。完整的应用程序代码如下 −

As usual, this view is added to the hello route, pointing to / URL. The complete application code is as follows −

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/ 。浏览器显示以下结果 −

Run the server and visit http://localhost:6543/. The browser shows following result −

hellotp

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

Every view must return a response object. The render_to_response() function is a shortcut function that actually returns a response object. This allows the hello_world view above to simply return the result of its call to render_to_response() directly.

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

On the other hand, pyramid.renderers.render() function renders a template to a string. We can manufacture a response object directly, and use that string as the body of the response.

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

Let us change the hello_world() view function as follows −

from pyramid.renderers import render

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

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

Remaining code being same, the browser also shows the same output as above.

Rendering via Configuration

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

As mentioned earlier, the content_type of HTTP response returned by Pyramid’s view callable id text/plain. However, it can be altered to string, JSON or JSONP if the renderer parameter of the @view_config decorator is assigned with any of these values. Pyramid thus have following built-in renderers −

  1. JSON

  2. String

  3. JSONP

Example

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

In the following example, the hello_world() view function is configured to render JSON response.

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 响应,如下图所示 −

The setting of renderer type to JSON also sets the content_type header of the HTTP response to application/json. The browser displays the JSON response as in the following figure −

json

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

The renderer parameter of the @view_config() decorator can be set to a template web page (which must be present in the templates folder). The prerequisite conditions are that the appropriate Python binding of the template library must be installed, and the application configuration must include the binding.

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

We have already installed python_jinja2 package, so that we can use jinja2 template to be rendered by the hello_world() view function, decorated by @view_config() with renderer parameter.

hello.jinja2 模板 HTML 代码如下 −

The hello.jinja2 template HTML code is as follows −

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

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

The decorated hello_world() function is written as −

from pyramid.view import view_config

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

Example

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

In this case, the view function returns a dictionary object. It is made available to the template as the context data, that can be inserted in the HTML text with the help of template language syntax elements.

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

The complete code to render a jinja2 template is as follows −

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 函数提供可变数据的模板网页如下所示 −

The template webpage with variable data supplied by the view function looks as below −

view

Add/Change Renderer

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

Templates are nothing but web pages interspersed with template language syntax. Even though Pyramid uses the default extension of a jinja2 template as ".jinja2", the established practice is to use the ".html" extension of web pages.

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

We can change the application configuration to let the .html extension be used in addition to ".jinja2". This is done by the add_jinja2_renderer.

config.add_jinja2_renderer(".html")

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

The hello.jinja2 template is now renamed as hello.html. To be able to use this template, let us change the view function definition to the following code −

from pyramid.view import view_config

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

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

Simultaneously, we modify the Configurator object’s properties by adding the ".html" renderer.

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 对象传递,而该对象反过来可以作为上下文数据传递给要渲染的模板。

As explained earlier, if the URL pattern in the route configuration consists of one or more placeholder parameters, their values from the request URL are passed along with the request as a matchdict object, which in turn can be passed as context data to the template to be rendered.

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

For our next example, the hello.html - the jinja2 template remains the same.

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

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

We know that the value for the context variable 'name' is passed by the view function. However, instead of passing a hardcoded value (as in the previous example), its value is fetched from the matchict object. This object is populated by the path parameters in the URL string.

from pyramid.view import view_config

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

Example

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

The modified application code is given below −

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 模板使用,并渲染出以下输出。

Start the server, open the browser and enter the URL http://localhost:6543/Tutorialspoint. The tailing string becomes the value of 'name' key in the matchdict. It is utilized by the jinja2 template and following output is rendered.

jinja2

Conditionals and Loops in Template

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

The jinja2 template language allows conditional statements and looping constructs to be included in the HTML script. The jinja2 syntax for these programming elements is as follows −

Conditionals

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

Loop

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

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

It can be seen that the jinja2 syntax is very much similar to Python’s if and for statements. Except that, jinja2 doesn’t use the indentations to mark the blocks. Instead, for each if there has to be an endif statement. Similarly, for each for statement, there has to be a endfor statement.

Example

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

Following example demonstrates the use of template conditional and loop statements. First, the Pyramid code uses a students as a list of dictionary objects, each dictionary having id, name and percentage of a student. This list object is passed as a context to the marklist.html template

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 语句语法显示通过/失败结果。

Save this program as marklist.py. Now, the following HTML script has to be save as marklist.html. It traverses the students list object received from the view function, and renders the student data in the form of a HTML table. The fourth column shows pass/fail result, using the jinja2 if statement syntax.

<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/ 链接渲染出以下表格结果 −

Run the marklist.py code. The http://localhost:6543/ link renders the following tabular result −

marklist