Python Pyramid - 快速指南


Python Pyramid - 概述

Pyramid 是一个用 Python 编写的开源、符合 WSGI 的 Web 框架。最初该项目名为 Pylons,但后来以新名称 Pyramid 发布。

  • Pyramid 是一个简约的 Web 框架。它不附带任何模板库,也不支持任何特定的数据库包。

  • 但是,它可以通过 SQLAlchemy 与 SQL 数据库集成,也可以与 Zope 对象数据库以及其他 NoSQL 数据库(例如 CouchDB)集成。

  • Pyramid 还可以配置为与 Mako、Jinja2 或 Chameleon 等模板库一起使用。

  • Pyramid 由Chris McDonough开发。Pyramid 的第一个版本于 2011 年 1 月发布。最新版本 Pyramid 2.0 已于 2021 年 3 月发布。

与其他Python框架的比较

Pyramid Web 应用程序框架受到 Zope 和 Django 框架的启发。因此,它结合了两者的最佳规定。

  • Pyramid 很大程度上基于repose.bfg框架。与 Pylons 项目合并后,于 2010 年更名为 Pyramid。

  • 扩展 Pyramid 应用程序的能力是从 Zope 库借来的。无需修改应用程序代码,就可以重用、修改或扩展应用程序。声明式安全层和路由遍历等功能继承自Zope。

  • 与 Pylons 1.0 的情况一样,Pyramid 不强制执行任何策略。它还允许用户选择任何数据库或模板系统 URL 调度方法也受到 Pylons 的启发。

  • 视图的概念基于 Django 的类似方法。丰富的文档也是 Pyramid 改编的 Django 功能之一。

  • 虽然定义并不完全符合,但 Pyramid 可以说遵循 MVC(模型-视图-控制器)方法。

Python Pyramid - 环境设置

建议在安装了Python 3.6或以上版本的系统上安装Pyramid包。Pyramid 可以安装在 Linux、MacOS 以及 Windows 平台上。最简单的安装方法是使用 PIP 安装程序,最好在 Python 虚拟环境下。

pip3 install pyramid

虽然 Pyramid Web 应用程序可以使用作为wsgiref模块一部分的内置 WSGI 开发服务器来运行,但不建议在生产环境中使用。因此,我们还安装了 Waitress,一个生产质量的纯 Python WSGI 服务器(也是 Pylons 项目的一部分)。

pip3 install waitress

这将安装 Pyramid(2.0 版)、Waitress(2.1.2 版)以及 Pylon 项目的其他依赖项(例如 WebOb、PasteDeploy 等)。要检查安装的内容,请运行 pip freeze 命令。

pip3 freeze
hupper==1.10.3
PasteDeploy==2.1.1
plaster==1.0
plaster-pastedeploy==0.7
pyramid==2.0
translationstring==1.4
venusian==3.0.0
waitress==2.1.2
WebOb==1.8.7
zope.deprecation==4.4.0
zope.interface==5.4.0

Python Pyramid - Hello World

例子

要检查 Pyramid 及其依赖项是否已正确安装,请使用任何支持 Python 的编辑器输入以下代码并将其另存为hello.py 。

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

def hello_world(request):
   return Response('Hello World!')
   
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()

需要配置器对象来定义 URL 路由并将视图函数绑定到它WSGI 应用程序对象是从此配置对象获取的,该对象是make_server()函数的参数以及本地主机的 IP 地址和端口。当调用serve_forever()方法时,服务器对象进入监听循环。

从命令终端运行该程序:

Python hello.py

输出

WSGI 服务器开始运行。打开浏览器,在地址栏输入http://localhost:6543/。当请求被接受时,hello_world()视图函数被执行。它返回 Hello world 消息。您将在浏览器窗口中看到 Hello world 消息。

你好世界

如前所述,wsgiref模块中的 make_server() 函数创建的开发服务器不适合生产环境。相反,我们将使用 Waitress 服务器。按照以下代码修改 hello.py -

from pyramid.config import Configurator
from pyramid.response import Response
from waitress import serve

def hello_world(request):
   return Response('Hello World!')
   
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('hello', '/')
      config.add_view(hello_world, route_name='hello')
      app = config.make_wsgi_app()
      serve(app, host='0.0.0.0', port=6543)

所有其他功能都是相同的,除了我们使用waitress模块的serve()函数来启动 WSGI 服务器。运行程序后在浏览器中访问“/”路由时,Hello world 消息将像以前一样显示。

除了函数之外,可调用类也可以用作视图。可调用类是重写__call__()方法的类。

from pyramid.response import Response
class MyView(object):
   def __init__(self, request):
      self.request = request
   def __call__(self):
      return Response('hello world')

Python Pyramid - 应用程序配置

Pyramid 应用程序对象有一个应用程序注册表,用于存储视图函数到路由的映射以及其他特定于应用程序的组件注册。Configurator 类用于构建应用程序注册表。

配置器生命周期由返回应用程序对象的上下文管理器管理。

with Configurator(settings=settings) as config:
   #configuration methods
   app = config.make_wsgi_app()

Configurator 类定义了以下重要方法来自定义应用程序 -

添加路由()

此方法注册 URL 调度的路由。使用以下参数 -

  • name - 第一个必需的位置参数必须是路线的唯一名称。该名称用于在注册视图或生成 URL 时标识路由。

  • pattern - 第二个必需的位置参数是表示 URL 路径的字符串,可选地包含用于解析 URL 中的变量数据的变量占位符。占位符由大括号括起来。例如,“/students/{id}”。

  • request_method - 该值可以是“GET”、“POST”、“HEAD”、“DELETE”、“PUT”之一。仅此类型的请求将与路由进行匹配。

添加视图()

此方法将视图配置添加到应用程序注册表。它将视图函数绑定到配置中存在的route_name 。所需的参数是 -

  • view - 视图函数的名称。

  • Route_name - 必须与路由配置声明的名称匹配的字符串。

  • request_method - 表示 HTTP REQUEST_METHOD 的字符串(例如“GET”、“POST”、“PUT”、“DELETE”、“HEAD”或“OPTIONS”),或包含一个或多个这些字符串的元组。

添加静态视图()

此方法添加一个用于渲染静态资源(例如图像和 CSS 文件)的视图,并使用以下参数 -

  • name - 该参数是一个字符串,表示与应用程序相关的本地 URL 前缀或完整 URL。

  • 路径- 此参数表示静态文件所在的磁盘路径。它的值可以是绝对路径或包相对路径。

该方法依次调用Configurator对象的add_route()方法。

add_notfound_view()

该方法添加一个视图,当当前请求找不到匹配的视图时要执行。以下代码显示了一个示例 -

from pyramid.config import Configurator
from pyramid.response import Response

def notfound(request):
   return Response('Not Found', status='404 Not Found')
   
config.add_notfound_view(notfound)

add_forbidden_​​view()

配置应用程序注册表,以便定义在引发 HTTPForbidden 异常时要执行的视图。参数列表包含对返回 403 状态响应的函数的引用。如果未提供参数,注册表将添加default_exceptionresponse_view()。

添加异常视图()

此方法会导致将异常视图功能添加到配置中,以针对指定的异常。

make_wsgi_app()

此方法返回 Pyramid WSGI 应用程序对象。

扫描()

这是一个用于注册视图的包装器。它导入所有寻找 @view_config 装饰器的应用程序模块。

对于每一个,它都会使用相同的关键字参数调用 config.add_view(view)。对 scan() 函数的调用执行对包和所有装饰的所有子包的扫描。

执行应用程序注册表配置的典型语句序列如以下代码片段所示 -

from pyramid.config import Configurator

with Configurator() as config:
   config.add_route('hello', '/')
   config.add_view(hello_world, route_name='hello')
   app = config.make_wsgi_app()

这种应用程序配置方法称为命令式配置。Pyramid提供了另一种配置方法,称为装饰配置。

声明式配置

有时,通过命令式代码进行配置变得很困难,特别是当应用程序代码分布在许多文件中时。声明式配置是一种方便的方法。Pyramid.view模型定义了view_config——一个函数、类或方法装饰器——它允许视图注册非常接近视图函数本身的定义。

为@view_config()装饰器提供了两个重要的参数。它们是route_namerequest_method。它们具有与Configurator 类的add_route()方法中相同的解释。它下面的函数被修饰,以便它绑定到添加到应用程序对象注册表中的路由。

下面给出的是hello_world()视图函数的声明性配置示例-

from pyramid.response import Response
from pyramid.view import view_config

@view_config(route_name='hello', request_method='GET')
def hello_world(request):
   return Response('Hello World!')

view_config 装饰器向 hello_world() 函数添加一个属性,使其可供稍后扫描找到。

例子

配置修饰和扫描调用的组合统称为声明性配置。以下代码使用声明性方法配置应用程序注册表。

scan() 函数发现路由及其映射视图,因此需要添加命令式配置语句。

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', request_method='GET')
def hello_world(request):
   return Response('Hello World!')
   
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('hello', '/')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

扫描器将 view_config 的参数转换为对 Pyramid.config.Configurator.add_view() 方法的调用,因此该操作相当于以下语句 -

config.add_view(hello_world, route_name='hello', request_method='GET')

输出

上述程序运行后,WSGI服务器启动。当浏览器访问链接 http://localhost:6543/ 时,将像以前一样呈现“Hello World”消息。

配置

Python Pyramid - URL 路由

在 MVC 架构出现之前,Web 应用程序使用将用户在浏览器中输入的 URL 映射到程序文件的机制,该程序文件的输出呈现为 HTML,作为返回浏览器的响应。Pyramid 框架使用一种路由机制,其中 URL 端点与应用程序注册表中注册的不同 URL 模式相匹配,调用其映射视图并呈现响应。

典型的 URL 由三部分组成: 协议(例如 http:// 或 https://),后跟 IP 地址或主机名。URL 的第一个/主机名之后的剩余部分称为路径或端点。

我的网站

端点后跟一个或多个可变部分形成路线。可变部分标识符由大括号括起来。例如,对于上面的 URL,路由为/blog/{id}

WSGI 应用程序充当路由器。它根据路由映射中存在的 URL 模式检查传入请求。如果找到匹配项,则执行其关联的视图可调用并返回响应。

路由配置

通过调用 Configurator 对象的 add_route() 方法将新路由添加到应用程序。路由有一个名称,它充当用于 URL 生成的标识符,以及一个用于与 URL 的 PATH_INFO 部分匹配的模式(方案和端口后面的部分,例如 URL 中的 /blog/1 http://example.com/blog/1)。

如前所述,add_route() 方法的模式参数可以有一个或多个由大括号括起来并用 / 分隔的占位符标识符。以下语句将“index”指定为“/{name}/{age}”模式的路由名称。

config.add_route('index', '/{name}/{age}')

要将可调用的视图关联到此路由,我们使用 add_view() 函数,如下所示 -

config.add_view(index, route_name='index')

index() 函数应该可用于与其匹配的路由。

def index(request):
   return Response('Root Configuration Example')

例子

我们将这些语句放在下面的程序中 -

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

def index(request):
   return Response('Root Configuration Example')
   
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('index', '/{name}/{age}')
      config.add_view(index, route_name='index')
      app = config.make_wsgi_app()
server = make_server('0.0.0.0', 6543, app)
server.serve_forever()

输出

运行上面的代码,在浏览器中访问http://localhost:6543/Ravi/21 。由于 URL 的 PATH_INFO 与索引路由匹配,因此显示以下输出 -

根配置

路由配置中使用的模式通常以正斜杠 (/) 字符开头。模式段(模式中的/ 个字符之间的单个项目)可以是文字字符串,也可以是占位符标记(例如,{name}),或两者的特定组合。替换标记前面不需要有 / 字符。

以下是路线模式的一些示例

/student/{name}/{marks}
/{id}/student/{name}/{marks}
/customer/{id}/item/{itemno}
/{name}/{age}

占位符标识符必须是有效的 Python 标识符。因此,它必须以大写或小写 ASCII 字母或下划线开头,并且只能包含大写或小写 ASCII 字母、下划线和数字。

路线匹配

当传入请求与与特定路由配置关联的 URL 模式匹配时,名为matchdict 的字典对象将添加为请求对象的属性。

request.matchdict包含与模式元素的替换模式匹配的值。matchdict中的键是字符串,而它们的值是 Unicode 对象。

在前面的示例中,将 index() 视图函数更改为以下 -

def index(request):
   return Response(str(request.matchdict))

浏览器以dict对象的形式显示路径参数。

参数

当请求与路由模式匹配时,传递给视图函数的请求对象还包含matched_route属性。匹配路由的名称可以从其 name 属性中获取。

例子

在下面的示例中,我们在@view.config()装饰器的帮助下定义了两个视图函数student_view()和book_view()。

应用程序的注册表配置为具有两个相应的路由 - 'student' 映射到'/student/{name}/{age}'模式,'book' 映射到'/book/{title}/{price}'模式。我们调用配置器对象的 scan() 方法来添加视图。

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='student')
def student_view(request):
   return Response(str(request.matchdict))
@view_config(route_name='book')
def book_view(request):
   title=request.matchdict['title']
   price=request.matchdict['price']
   return Response('Title: {}, Price: {}'.format(title,price))
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('student', '/student/{name}/{age}')
      config.add_route('book', '/book/{title}/{price}')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

输出

当浏览器输入http://localhost:6543/student/Ravi/21 URL 时,输出为

{'name': 'Ravi', 'age': '21'}

如果输入的 URL 是http://localhost:6543/book/Python/300,则输出为

Title: Python, Price: 300

Python Pyramid - 查看配置

术语“视图配置”是指将可调用视图(函数、方法或类)与路由配置信息相关联的机制。Pyramid 找到给定 URL 模式的最佳可调用项。

配置视图有三种方法-

  • 使用 add_view() 方法

  • 使用 @view_config() 装饰器

  • 使用@view_defaults()类装饰器

使用 add_view() 方法

这是通过调用Configurator对象的add_view()方法来强制配置视图的最简单方法。

该方法使用以下参数 -

  • name - 匹配此可调用视图所需的视图名称。如果未提供名称,则使用空字符串(表示默认视图)。

  • context - 此资源必须是 Python 类的对象才能找到并调用此视图。如果未提供上下文,则使用与任何资源匹配的值 None。

  • Route_name - 该值必须与路由配置声明的名称匹配,在调用此视图之前必须匹配该路由配置声明的名称。如果提供了route_name,则仅当命名路由匹配时才会调用可调用视图。

  • request_type - 请求必须提供的接口,以便找到和调用该视图。

  • request_method - 表示 HTTP REQUEST_METHOD 的字符串(例如“GET”、“POST”、“PUT”、“DELETE”、“HEAD”或“OPTIONS”)或包含一个或多个这些字符串的元组。仅当请求的方法属性与提供的值匹配时才会调用视图。

  • request_param - 该参数可以是任何字符串或字符串序列。仅当 request.params 字典具有与提供的值匹配的键时才会调用该视图。

例子

在以下示例中,定义了两个函数getview()postview()并将其与两个同名路由关联。这些函数仅返回调用它们的 HTTP 方法的名称。

当使用 GET 方法请求URL /get时,将调用 getview() 函数。类似地,postview() 函数在POST 方法请求/post路径 id时执行。

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
def getview(request):
   ret=request.method
   return Response('Method: {}'.format(ret))
def postview(request):
   ret=request.method
   return Response('Method: {}'.format(ret))
   
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('getview', '/get')
      config.add_route('postview', '/post')
      config.add_view(getview, route_name='getview',request_method='GET')
      config.add_view(postview,route_name='postview', request_method='POST')
      app = config.make_wsgi_app()
      server = make_server('0.0.0.0', 6543, app)
      server.serve_forever()

虽然可以使用 Web 浏览器作为 HTTP 客户端来发送 GET 请求,但不能将其用于 POST 请求。因此,我们使用 CURL 命令行实用程序。

C:\Users\Acer>curl localhost:6543/get
Method: GET
C:\Users\Acer>curl -d "param1=value1" -H "Content-Type: application/json" -X POST http://localhost:6543/post
Method: POST

如前所述,request_method参数可以是一个或多个 HTTP 方法的列表。让我们修改上面的程序并定义一个oneview()函数来标识导致其执行的 HTTP 方法。

def oneview(request):
   ret=request.method
   return Response('Method: {}'.format(ret))

此函数在所有 HTTP 方法的应用程序配置中注册。

config.add_route('oneview', '/view')
config.add_view(oneview, route_name='oneview',
   request_method=['GET','POST', 'PUT', 'DELETE'])

输出

CURL 输出如下所示 -

C:\Users\Acer>curl localhost:6543/view
Method: GET
C:\Users\Acer>curl -d "param1=value1" -H "Content-Type: application/json" -X POST http://localhost:6543/view
Method: POST
C:\Users\Acer>curl -d "param1=value1" -H "Content-Type: application/json" -X PUT http://localhost:6543/view
Method: PUT
C:\Users\Acer>curl -X DELETE http://localhost:6543/view
Method: DELETE

使用 @view_config() 装饰器

@view_config 装饰器可以用来将配置的路由与函数、方法甚至可调用类关联起来,而不是强制添加视图。

例子

如声明性配置部分所述,注册的路由可以与函数关联,如下例所示 -

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')
def hello_world(request):
   return Response('Hello World!')
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('hello', '/')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

请注意,只有在调用 scan() 方法后,视图才会添加到应用程序配置中。虽然无需强制添加视图,但性能可能会稍微慢一些。

输出

view_config() 装饰器也可以被赋予与 add_view() 方法相同的参数。所有参数都可以省略。

@view_config()
def hello_world(request):
   return Response('Hello World!')

在这种情况下,该函数将使用任何路由名称、任何请求方法或参数进行注册。

view_config 装饰器放置在可调用视图函数的定义之前,如上面的示例所示。如果要用作可调用视图,也可以将其放在类的顶部。这样的类必须有一个 __call__() 方法。

在以下 Pyramid 应用程序代码中,MyView类用作可调用对象,并由@view_config装饰器装饰。

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')
class MyView(object):
   def __init__(self, request):
      self.request = request
      
   def __call__(self):
      return Response('hello World')
      
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('hello', '/')
      #config.add_view(MyView, route_name='hello')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

请注意,我们可以通过显式调用 add_view() 方法来添加视图,而不是扫描视图配置。

例子

如果类中的方法必须与不同的路由关联,则应在每个方法之上使用单独的 @view_config(),如以下示例所示。在这里,我们有两个方法绑定到两个单独的路由。

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

class MyView(object):
   def __init__(self, request):
      self.request = request
      
   @view_config(route_name='getview', request_method='GET')
   def getview(self):
      return Response('hello GET')
   @view_config(route_name='postview', request_method='POST')
   def postview(self):
      return Response('hello POST')
      
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('getview', '/get')
      config.add_route('postview', '/post')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

输出

这是 CURL 命令的输出 -

C:\Users\Acer>curl localhost:6543/get
hello GET
C:\Users\Acer>curl -d "param1=value1" -H "Content-Type: application/json" -X POST http://localhost:6543/post
hello POST

使用 @view_defaults() 装饰器

view_defaults()是一个类装饰器。如果您必须将类中的方法添加为具有一些公共参数和一些特定参数的视图,则可以在类顶部的view_defaults()装饰器中指定公共参数,通过单独的view_config()对每个方法进行配置在他们每一个人面前。

例子

在下面的代码中,我们有不同的方法响应相同的路由,但使用不同的request_method。因此,我们将路由名称定义为默认值,并在每个视图配置中指定request_method 。

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

@view_defaults(route_name='myview')
class MyView(object):
   def __init__(self, request):
      self.request = request
      
   @view_config( request_method='GET')
   def getview(self):
      return Response('hello GET')
   @view_config(request_method='POST')
   def postview(self):
      return Response('hello POST')
   @view_config(request_method='PUT')
   def putview(self):
      return Response('hello PUT')
   @view_config(request_method='DELETE')
   def delview(self):
      return Response('hello DELETE')
      
if __name__ == '__main__':
   with Configurator() as config:
      config.add_route('myview', '/view')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

输出

向服务器发出不同 HTTP 请求的 CURL 命令如下 -

C:\Users\Acer>curl localhost:6543/view
hello GET
C:\Users\Acer>curl -d "param1=value1" -H "Content-Type: application/json" -X POST http://localhost:6543/view
hello POST
C:\Users\Acer>curl -d "param1=value1" -H "Content-Type: application/json" -X PUT http://localhost:6543/view
hello PUT
C:\Users\Acer>curl -X DELETE http://localhost:6543/view
hello DELETE

Python Pyramid - 路由前缀

很多时候,相似的 URL 模式会在多个 Python 代码模块中注册不同的路由。例如,我们有一个Student_routes.py,其中 /list 和 /add URL 模式注册为“list”和“add”路由。与这些路由关联的视图函数分别是list()add()

#student_routes.py
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config

@view_config( route_name='add')
def add(request):
   return Response('add student')
@view_config(route_name='list')
def list(request):
   return Response('Student list')
   
def students(config):
   config.add_route('list', '/list')
   config.add_route('add', '/add')
   config.scan()

这些路由最终将在调用Students()函数时注册。

同时,还有 book_routes.py,其中相同的 URL /listadd/被注册到 'show' 和 'new' 路由。它们的关联视图分别是list()和add()。该模块有 books() 函数,可以添加路线。

#book_routes.py
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config

@view_config( route_name='new')
def add(request):
   return Response('add book')
@view_config(route_name='show')
def list(request):
   return Response('Book list')
def books(config):
   config.add_route('show', '/list')
   config.add_route('new', '/add')
   config.scan()

显然,URL 模式之间存在冲突,因为“/list”和“/add”分别指向两个路由,必须解决此冲突。这是通过使用config.include()方法的route_prefix参数来完成的。

config.include() 的第一个参数是添加路由的函数,第二个参数是route_prefix 字符串,它将被添加到包含函数中使用的 URL 模式之前。

因此,声明

config.include(students, route_prefix='/student')

将导致“/list”URL 模式更改为“/student/list”,“/add”变为“student/add”。同样,我们可以在 books() 函数中为这些 URL 模式添加前缀。

config.include(books, route_prefix='/books')

例子

启动服务器的代码如下 -

from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from student_routes import students
from book_routes import books

if __name__ == '__main__':
   with Configurator() as config:
      config.include(students, route_prefix='/student')
      config.include(books, route_prefix='/book')
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

输出

让我们运行上面的代码并通过以下 CURL 命令测试路由。

C:\Users\Acer>curl localhost:6543/student/list
Student list
C:\Users\Acer>curl localhost:6543/student/add
add student
C:\Users\Acer>curl localhost:6543/book/add
add book
C:\Users\Acer>curl localhost:6543/book/list
Book list

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绑定 默认扩展名
变色龙 Pyramid变色龙 .pt、.txt
金贾2 Pyramid_jinja2 .jinja2
真子 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 脚本保存为templates文件夹中的hello.jinja2

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

Jinja2 模板库

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

表达式

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

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

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

条件句

  • {% if expr %}

  • {% 别的 %}

  • {% 万一 %}

环形

  • {% for var in iterable %}

  • {% 结束 %}

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

你好TP

每个视图都必须返回一个响应对象。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 的 view callable id text/plain 返回的 HTTP 响应的 content_type。但是,如果为 @view_config 装饰器的渲染器参数分配了这些值中的任何一个,则可以将其更改为字符串、JSON 或 JSONP。因此,Pyramid有以下内置渲染器 -

  • JSON

  • 细绳

  • 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() 视图函数进行渲染,并通过 @view_config() 和 renderer 参数进行装饰。

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

输出

具有由视图函数提供的可变数据的模板网页如下所示 -

看法

添加/更改渲染器

模板只不过是散布着模板语言语法的网页。尽管 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”渲染器来修改配置器对象的属性。

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 模板使用并呈现以下输出。

金贾2

模板中的条件和循环

jinja2 模板语言允许将条件语句和循环结构包含在 HTML 脚本中。这些编程元素的 jinja2 语法如下 -

条件句

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

环形

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

可以看出jinja2语法与Python的if和for语句非常相似。除此之外,jinja2 不使用缩进来标记块。相反,对于每个 if 都必须有一个 endif 语句。同样,对于每个 for 语句,都必须有一个 endfor 语句。

例子

以下示例演示了模板条件和循环语句的使用。首先,Pyramid代码使用学生作为字典对象列表,每个字典都有学生的 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。它遍历从视图函数接收到的学生列表对象,并以 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/链接呈现以下表格结果 -

标记列表

Python Pyramid - HTML 表单模板

在本章中,我们将了解 Pyramid 如何从 HTML 表单读取数据。让我们将以下 HTML 脚本保存为myform.html。我们将使用它来获取 Template 对象并渲染它。

<html>
<body>
   <form method="POST" action="http://localhost:6543/students">
   <p>Student Id: <input type="text" name="id"/> </p>
   <p>student Name: <input type="text" name="name"/> </p>
   <p>Percentage: <input type="text" name="percent"/> </p>
   <p><input type="submit" value="Submit"> </p>
</body>
</html>

在 Pyramid 对象的配置中添加的“index”路由映射到以下 index() 函数,该函数呈现上述 HTML 表单 -

@view_config(route_name='index', renderer='templates/myform.html')
def index(request):
   return {}

我们可以看到,用户输入的数据通过 POST 请求传递到 /students URL。因此,我们将添加一个“students”路由来匹配 /students 模式,并将其与 add() 视图函数关联,如下所示 -

@view_config(route_name='students', renderer='templates/marklist.html')
def add(request):
   student={'id':request.params['id'], 
      'name':request.params['name'],
      'percent':int(request.params['percent'])} 9. Pyramid – HTML Form Template
   students.append(student)
   return {'students':students}

POST 请求发送的数据以request.params对象的形式存在于 HTTP 请求对象中。它是 HTML 表单属性及其用户输入的值的字典。该数据被解析并附加到学生字典对象列表中。更新后的学生对象作为上下文数据传递到 marklist.html 模板。

marklist.html Web 模板与前面示例使用的相同。它显示学生数据表以及计算结果列。

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

例子

下面给出了完整的代码,其中包含用于渲染 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/myform.html')
def index(request):
   return {}
@view_config(route_name='students', renderer='templates/marklist.html')
def add(request):
   student={'id':request.params['id'], 'name':request.params['name'],
'percent':int(request.params['percent'])}
   students.append(student)
   return {'students':students}

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

输出

要启动服务器,请从命令行运行上述 Python 代码。在浏览器中,访问http://localhost:6543/获取如下所示的表单 -

学生

输入如图所示的示例数据,然后按提交按钮。浏览器被定向到 /students URL,该 URL 又调用add()视图。结果是一个标记列表表,显示新学生新输入的数据。

学生网址

Python Pyramid - 静态资源

通常需要在模板响应中包含一些即使存在某些动态数据也保持不变的资源。此类资源称为静态资产。媒体文件(.png、.jpg 等)、用于执行某些前端代码的 JavaScript 文件或用于格式化 HTML(.css 文件)的样式表都是静态文件的示例。

Pyramid 将这些静态资源从服务器文件系统中的指定目录提供给客户端浏览器。Configurator 对象的add_static_view ()方法定义包含静态文件(例如图像、JavaScript 和 CSS 文件)的文件夹的路由名称和路径。

作为约定,“static”目录用于存储静态资源,并且 add_static_view() 的用法如下 -

config.add_static_view(name='static', path='static')

定义静态路由后,在HTML脚本中使用时可以通过request.static_url()方法获取静态资源的路径。

静态图像

在以下示例中,Pyramid徽标将在 logo.html 模板中呈现。因此,“pyramid.png”文件首先放置在静态文件夹中。现在可以在 HTML 代码中用作 <img> 标记的 src 属性。

<html>
<body>
   <h1>Hello, {{ name }}. Welcome to Pyramid</h1>
   <img src="{{request.static_url('app:static/pyramid.png')}}">
</body>
</html>

例子

应用程序代码使用add_static_view()更新配置器,并定义index()视图呈现上述模板。

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/logo.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.add_static_view(name='static', path='app:static')
      config.scan()
      app = config.make_wsgi_app()
   server = make_server('0.0.0.0', 6543, app)
   server.serve_forever()

输出

运行上面的代码来启动服务器。在浏览器中使用http://localhost:6543/Guest作为 URL。这里“Guest”是由matchdict对象中的视图函数拾取的路径参数,并作为上下文传递给 logo.html 模板。浏览器现在显示Pyramid徽标。

Pyramid

Javascript 作为静态资源

这是静态文件的另一个示例。JavaScript 代码hello.js包含要在以下 HTML 脚本 (templates\hello.html) 中的onload事件上执行的myfunction()的定义

<html>
<head>
   <script src="{{request.static_url('app:static/hello.js')}}"></script>
</head>
<body onload="myFunction()">
   <div id="time" style="text-align:right; width="100%"></div>
   <h1><div id="ttl">{{ name }}</div></h1>
</body>
</html>

例子

保存在静态文件夹中的hello.js代码如下 -

function myFunction() {
   var today = new Date();
   var h = today.getHours();
   var m = today.getMinutes();
   var s = today.getSeconds();
   var msg="";
   if (h<12)
   {
      msg="Good Morning, ";
   }
   if (h>=12 && h<18)
   {
      msg="Good Afternoon, ";
   }
   if (h>=18)
   {
      msg="Good Evening, ";
   }
   var x=document.getElementById('ttl').innerHTML;
   document.getElementById('ttl').innerHTML = msg+x;
   document.getElementById('time').innerHTML = h + ":" + m + ":" + s;
}

输出

该函数检测当前时间的值,并根据一天中的时间为msg变量分配适当的值(早上好、下午好或晚上好)。

将hello.js保存在static文件夹中,将 hello.html 保存在templates文件夹中,然后重新启动服务器。浏览器应显示当前时间及其下方相应的消息。

晚上好

Python Pyramid - 请求对象

可调用视图的功能涉及从 WSGI 环境获取请求数据,并在处理后将某个 HTTP 响应返回给客户端。视图函数接收 Request 对象作为参数。

通常该对象不是由用户实例化的。相反,它封装了 WSGI 环境字典。该请求对象代表“pyramid.request.Request 类”。它拥有许多属性和方法,视图函数使用这些属性和方法处理请求数据。

以下是一些属性-

  • request.method - 客户端发送数据所使用的 HTTP 请求方法,例如 GET、POST

  • request.GET - 该属性是包含查询字符串中所有变量的多重字典。

  • request.POST - 仅当请求是 POST 并且是表单提交时,此属性才可用。它是一个包含请求正文中所有变量的多重字典。

  • request.params - request.GET 和 request.POST 中所有内容的组合多重字典。

  • request.body - 该属性包含整个请求正文作为字符串。当请求是不是表单提交的 POST 或类似 PUT 的请求时,这非常有用。

  • request.cookies - 包含所有cookie。

  • request.headers - 所有 HTTP 标头的不区分大小写的字典。

除了上述HTTP特定环境属性之外,Pyramid还添加了某些特殊属性。

  • request.url - 返回带有查询字符串的完整请求 URL,例如 http://localhost:6543/app?name=Ravi

  • request.host - URL 中的主机信息,例如 localhost

  • request.host_url - 此属性返回主机的 URL,例如 http://localhost:6543/

  • request.application_url - 应用程序的 URL(不带 PATH_INFO),例如 http://localhost:6543/app

  • request.path_url - 包含应用程序的 URL,包括 PATH_INFO,例如 http://localhost:66543/app

  • request.path - 返回包含 PATH_INFO 且不含主机的 URL,例如“/app”

  • request.path_qs - URL 中的查询字符串,包括 PATH_INFO,例如“/app?name=Ravi”

  • request.query_string - 仅 URL 中的查询字符串,例如“name=Ravi”

Python Pyramid - 响应对象

Response 类在 Pyramid.response 模块中定义。此类的对象由视图可调用返回。

from pyramid.response import Response
def hell(request):
   return Response("Hello World")

响应对象包含状态代码(默认为 200 OK)、响应标头列表和响应正文。大多数 HTTP 响应标头都可作为属性使用。以下属性可用于响应对象 -

  • response.content_type - 内容类型是一个字符串,例如 – response.content_type = 'text/html'。

  • response.charset - 它还通知response.text中的编码。

  • response.set_cookie - 该属性用于设置 cookie。需要给出的参数是名称、值和 max_age。

  • response.delete_cookie - 从客户端删除 cookie。实际上,它将 max_age 设置为 0,并将 cookie 值设置为“”。

Pyramid.httpExceptions模组_