快速参观Pyramid¶
Pyramid让你从小处开始,大处结束。这个 Quick Tour Pyramid是为那些想要评估Pyramid的人设计的,不管你是刚接触到PythonWeb框架的人,还是急于成为专业人士的人。对于每个主题的更详细的处理,请给出 Pyramid快速教程 尝试一下。
如果希望剪切和粘贴此教程中的示例代码,可以浏览位于 Pyramid repository in the directory "docs/quick_tour" <https://github.com/Pylons/pyramid/> . 如果您已经下载了源代码,您将在同一位置找到tour。
安装¶
一旦您有了标准的Python环境设置,开始使用Pyramid就轻而易举了。不幸的是,在Python中,“标准”并不是那么简单。对于这个快速旅行,它意味着 Python , venv
, pip 和 Setuptools .
为了节省一点输入时间,并确保使用安装在虚拟环境中的模块、脚本和包,我们还将设置一个环境变量。
例如,对于Linux上的python 3:
# set an environment variable to where you want your virtual environment $ export VENV=~/env # create the virtual environment $ python3 -m venv $VENV # install pyramid $ $VENV/bin/pip install pyramid # or for a specific released version $ $VENV/bin/pip install "pyramid==2.0.2"
对于Windows:
# set an environment variable to where you want your virtual environment c:\> set VENV=c:\env # create the virtual environment c:\> python -m venv %VENV% # install pyramid c:\> %VENV%\Scripts\pip install pyramid # or for a specific released version c:\> %VENV%\Scripts\pip install "pyramid==2.0.2"
从2.0版开始,Pyramid仅在Python3上运行。为了简单起见,剩下的示例将只显示unix命令。
你好世界¶
微框架研究表明,学习最好从一个非常小的第一步开始。下面是Pyramid中的一个小应用程序:
1from wsgiref.simple_server import make_server
2from pyramid.config import Configurator
3from pyramid.response import Response
4
5
6def hello_world(request):
7 return Response('Hello World!')
8
9
10if __name__ == '__main__':
11 with Configurator() as config:
12 config.add_route('hello', '/')
13 config.add_view(hello_world, route_name='hello')
14 app = config.make_wsgi_app()
15 server = make_server('0.0.0.0', 6543, app)
16 server.serve_forever()
这个简单的例子很容易运行。将此保存为 app.py
运行它:
$ $VENV/bin/python ./app.py
接下来在浏览器中打开http://localhost:6543/,您将看到 Hello World!
消息。
不熟悉python web编程?如果是这样的话,模块中的一些行将进行价值解释:
Lines 6-7 . 实现生成 response .
Line 10 .
if __name__ == '__main__':
是python的说法“从命令行运行时从这里开始”。Lines 11-13 . 使用Pyramid's configurator 在一个 context manager 连接 view 特定URL的代码 route .
Lines 14-16 . 发表一篇文章 WSGI 使用HTTP服务器的应用程序。
如本例所示, configurator 在金字塔发展中起着核心作用。从松散耦合的部分通过 应用程序配置 是金字塔中的一个中心思想,我们将定期在此重访 快速旅游 .
处理Web请求和响应¶
为Web开发意味着处理Web请求。由于这是Web应用程序的关键部分,因此Web开发人员需要一套功能强大、成熟的Web请求软件。
Pyramid一直很好地适应了现有的python web开发世界(虚拟环境、打包、cookiecutters,第一个使用python 3的公司之一,等等)。Pyramid变成了著名的 WebOb 用于请求和响应处理的python库。在上面的例子中,Pyramid手 hello_world
一 request
那就是 based on WebOb .
让我们看看请求和响应的一些功能:
def hello_world(request):
# Some parameters from a request such as /?name=lisa
url = request.url
name = request.params.get('name', 'No Name Provided')
body = 'URL %s with name: %s' % (url, name)
return Response(
content_type="text/plain",
body=body
)
在这个Pyramid视图中,我们从 request.url
. 如果您访问了http://localhost:6543/?name=alice在浏览器中,名称包含在响应的正文中:
URL http://localhost:6543/?name=alice with name: alice
最后,我们设置响应的内容类型,并返回响应。
参见
意见¶
对于上面的示例, hello_world
功能是一个“视图”。在Pyramid视图中,是接受Web请求和返回响应的主要方式。
到目前为止,我们的示例将所有内容放在一个文件中:
视图功能
它在配置程序中的注册
将其映射到URL的路由
wsgi应用程序启动程序
让我们将视图移到它们自己的视图中 views.py
模块和更改 app.py
要扫描该模块,请查找设置视图的装饰器。
首先我们修订了 app.py
:
1from wsgiref.simple_server import make_server
2from pyramid.config import Configurator
3
4if __name__ == '__main__':
5 with Configurator() as config:
6 config.add_route('home', '/')
7 config.add_route('hello', '/howdy')
8 config.add_route('redirect', '/goto')
9 config.add_route('exception', '/problem')
10 config.scan('views')
11 app = config.make_wsgi_app()
12 server = make_server('0.0.0.0', 6543, app)
13 server.serve_forever()
我们添加了更多的路由,但也删除了视图代码。我们的视图及其注册(通过装饰器)现在位于一个模块中 views.py
,通过扫描 config.scan('views')
.
我们现在有一个 views.py
重点处理请求和响应的模块:
1from html import escape
2
3from pyramid.httpexceptions import HTTPFound
4from pyramid.response import Response
5from pyramid.view import view_config
6
7
8# First view, available at http://localhost:6543/
9@view_config(route_name='home')
10def home_view(request):
11 return Response('<p>Visit <a href="/howdy?name=lisa">hello</a></p>')
12
13
14# /howdy?name=alice which links to the next view
15@view_config(route_name='hello')
16def hello_view(request):
17 name = request.params.get('name', 'No Name')
18 body = '<p>Hi %s, this <a href="/goto">redirects</a></p>'
19 # Python html.escape to prevent Cross-Site Scripting (XSS) [CWE 79]
20 return Response(body % escape(name))
21
22
23# /goto which issues HTTP redirect to the last view
24@view_config(route_name='redirect')
25def redirect_view(request):
26 return HTTPFound(location="/problem")
27
28
29# /problem which causes a site error
30@view_config(route_name='exception')
31def exception_view(request):
32 raise Exception()
我们有四种观点,每种观点都是相互引导的。如果从http://localhost:6543/开始,将得到一个响应,其中包含指向下一个视图的链接。这个 hello_view
(网址为 /howdy
)链接到 redirect_view
,将发出重定向到最终视图。
早些时候我们看到 config.add_view
作为配置视图的一种方法。本节介绍 @view_config
. Pyramid的配置支持 imperative configuration ,比如 config.add_view
在上一个示例中。您也可以使用 declarative configuration 其中一条 Python decorator 放置在视图上方的行上。这两种方法都会产生相同的最终配置,因此通常只是一个简单的品味问题。
参见
参见: Quick Tutorial Views , 意见 , 查看配置 和 调试视图配置 .
路由¶
编写Web应用程序通常意味着复杂的URL设计。我们刚刚看到一些Pyramid的请求和意见。让我们看看有助于路由的功能。
上面我们看到了将URL路由到Pyramid中视图的基础知识:
项目的“设置”代码注册了一个路由名称,以便在匹配部分URL时使用。
在其他地方,视图被配置为调用该路由名称。
备注
为什么要这样做两次?其他的PythonWeb框架允许您创建一个路由,并在一个步骤中将其与视图关联。如中所示 路由需要相对排序 ,多个路由可能匹配相同的URL模式。Pyramid并没有提供帮助猜测的方法,而是让您在排序时更加明确。Pyramid还提供了避免这个问题的设施。
如果我们希望URL的一部分在我的视图中作为数据可用怎么办?我们可以使用此路由声明,例如:
6 config.add_route('hello', '/howdy/{first}/{last}')
使用此,URL如 /howdy/amy/smith
将分配 amy
到 first
和 smith
到 last
. 然后我们可以在我们的视图中使用这些数据:
5@view_config(route_name='hello')
6def hello_world(request):
7 body = '<h1>Hi %(first)s %(last)s!</h1>' % request.matchdict
8 return Response(body)
request.matchdict
包含URL中与路由声明中的“替换模式”(大括号)匹配的值。然后可以在视图中使用此信息。
参见
参见: Quick Tutorial Routing , URL调度 , 调试路由匹配 和 请求处理 .
模板法¶
哎哟。我们一直在创造自己的 Response
并用HTML填充响应体。通常不会在Python中直接嵌入HTML字符串,而是使用模板语言。
Pyramid并不要求特定的数据库系统、表单库等。它鼓励可替换性。这同样适用于模板化,这是幸运的:开发人员对模板语言有很强的看法。也就是说,塔架项目正式支持变色龙、jinja2和Mako的捆绑。在这一步中,让我们使用变色龙。
让我们添加 pyramid_chameleon
Pyramid add-on 使变色龙成为 renderer 在我们的Pyramid应用程序中:
$VENV/bin/pip install pyramid_chameleon
安装包后,我们可以将模板绑定包含到配置中 app.py
:
6 config.add_route('hello', '/howdy/{name}')
7 config.include('pyramid_chameleon')
8 config.scan('views')
现在让我们改变我们的 views.py
文件:
1from pyramid.view import view_config
2
3
4@view_config(route_name='hello', renderer='hello_world.pt')
5def hello_world(request):
6 return dict(name=request.matchdict['name'])
啊,看起来好多了。我们有一个关注Python代码的视图。我们的 @view_config
decorator指定 renderer 指向我们的模板文件。然后,我们的视图只返回数据,这些数据随后被提供给我们的模板。 hello_world.pt
:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Quick Glance</title>
</head>
<body>
<h1>Hello ${name}</h1>
</body>
</html>
因为我们的观点回来了 dict(name=request.matchdict['name'])
我们可以使用 name
作为模板中的变量,通过 ${{name}}
.
参见
参见: Quick Tutorial Templating , 模板 , 调试模板 和 可用的附加模板系统绑定 .
jinja2模板¶
我们只是说Pyramid不喜欢一种模板语言而不是另一种。是时候证明了。Jinja2是一个流行的模板系统,仿照Django的模板。让我们添加 pyramid_jinja2
Pyramid add-on 使Jinja2成为 renderer 在我们的Pyramid应用中:
$VENV/bin/pip install pyramid_jinja2
安装包后,我们可以将模板绑定包含到配置中:
6 config.add_route('hello', '/howdy/{name}')
7 config.include('pyramid_jinja2')
8 config.scan('views')
我们视图中唯一的变化是将渲染器指向 .jinja2
文件:
4@view_config(route_name='hello', renderer='hello_world.jinja2')
5def hello_world(request):
6 return dict(name=request.matchdict['name'])
我们的jinja2模板与之前的模板非常相似:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello {{ name }}!</h1>
</body>
</html>
Pyramid的模板附加组件在应用程序中注册了一种新的渲染器。渲染器注册映射到不同类型的文件扩展名。在这种情况下,将扩展名从 .pt
到 .jinja2
通过 pyramid_jinja2
渲染器。
参见
参见: Quick Tutorial Jinja2 , Jinja2 homepage 和 pyramid_jinja2 Overview .
Static Assets¶
当然,网络不仅仅是标记。您需要Static Assets:css、js和images。让我们将Web应用程序指向一个目录,从中Pyramid将提供一些Static Assets。首先,我们让我们再次调用 configurator in app.py
:
6 config.add_route('hello', '/howdy/{name}')
7 config.add_static_view(name='static', path='static')
8 config.include('pyramid_jinja2')
这会告诉我们的wsgi应用程序将http://localhost:6543/static/下的请求映射到 static
我们的python模块旁边的目录。
接下来,创建一个名为``static`` 的目录,并将“app.css
放在其中
body {
margin: 2em;
font-family: sans-serif;
}
我们现在要做的就是在 <head>
我们的Jinja2模板, hello_world.jinja2
:
4 <title>Hello World</title>
5 <link rel="stylesheet" href="/static/app.css"/>
6</head>
此链接假定我们的CSS位于以 /static/
. 如果网站后来被移到 /somesite/static/
?或者可能是Web开发人员更改了磁盘上的排列?Pyramid提供了一个帮助器,允许在URL生成上实现灵活性:
4 <title>Hello World</title>
5 <link rel="stylesheet" href="{{ request.static_url('__main__:static/app.css') }}"/>
6</head>
通过使用 request.static_url
要生成Static Assets的完整URL,请确保与配置保持同步,并在以后获得重构灵活性。
参见
参见: Quick Tutorial Static Assets , 静态资产 , 阻止HTTP缓存 和 影响HTTP缓存 .
回到JSON¶
现代Web应用程序不仅仅是呈现的HTML。动态页面现在使用JavaScript通过请求服务器数据作为JSON来更新浏览器中的UI。Pyramid通过JSON渲染器支持这一点:
9@view_config(route_name='hello_json', renderer='json')
10def hello_json(request):
11 return [1, 2, 3]
这连接了一个通过JSON返回一些数据的视图。 renderer 它调用Python的JSON支持将数据序列化为JSON,并设置相应的HTTP头。
我们还需要添加一条路线到 app.py
以便我们的应用程序知道如何响应 hello.json
.
6 config.add_route('hello', '/howdy/{name}')
7 config.add_route('hello_json', 'hello.json')
8 config.add_static_view(name='static', path='static')
参见
参见: Quick Tutorial JSON , 正在写入使用渲染器的视图可调用文件 , JSON渲染器 和 添加和更改渲染器 .
视图类¶
到目前为止,我们的观点是简单的、独立的功能。很多时候你的观点是相关的。它们可能有不同的方法来查看或处理相同的数据,或者它们可能是一个处理多个操作的RESTAPI。将这些分组为 view class 有意义,实现以下目标。
组视图
集中一些重复的默认值
分享一些州和帮助者
下面显示了一个“Hello World”示例,其中包含三个操作:查看表单、保存更改或按 views.py
:
7# One route, at /howdy/amy, so don't repeat on each @view_config
8@view_defaults(route_name='hello')
9class HelloWorldViews:
10 def __init__(self, request):
11 self.request = request
12 # Our templates can now say {{ view.name }}
13 self.name = request.matchdict['name']
14
15 # Retrieving /howdy/amy the first time
16 @view_config(renderer='hello.jinja2')
17 def hello_view(self):
18 return dict()
19
20 # Posting to /howdy/amy via the "Edit" submit button
21 @view_config(request_param='form.edit', renderer='edit.jinja2')
22 def edit_view(self):
23 print('Edited')
24 return dict()
25
26 # Posting to /howdy/amy via the "Delete" submit button
27 @view_config(request_param='form.delete', renderer='delete.jinja2')
28 def delete_view(self):
29 print('Deleted')
30 return dict()
如您所见,这三个视图在逻辑上分组在一起。明确地:
当您转到
/howdy/amy
. 此URL映射到hello
我们使用可选的@view_defaults
.当表单数据包含具有
form.edit
,例如单击<input type="submit" name="form.edit" value="Save">
. 此规则在中指定@view_config
为了这个观点。单击按钮时返回第三个视图,如
<input type="submit" name="form.delete" value="Delete">
.
只需要一条路线,在视图类顶部的一个位置中声明。此外,转让 name
是在 __init__
功能。然后我们的模板可以使用 {{{{ view.name }}}}
.
Pyramid视图类与内置谓词和自定义谓词相结合,提供了更多的功能:
所有与功能视图相同的视图配置参数
基于请求中的信息或数据(如
request_param
,request_method
,accept
,header
,xhr
,containment
,和自定义谓词。
参见
参见: View Classes 和 More View Classes 在快速教程中, 将可调用视图定义为类 和 查看和路由谓词 .
应用程序运行方式 pserve
¶
在CookiCutter之前,我们的项目在代码中混合了许多操作细节。为什么我的主代码应该关心我想要的HTTP服务器和运行的端口号?
pserve
是Pyramid的应用程序运行程序,将操作细节与代码分开。当你安装Pyramid时,一个叫做 pserve
是写给你的 bin
目录。这个程序是一个可执行的python模块。它非常小,通过进口获得大部分大脑。
你可以跑 pserve
具有 --help
看看它的一些选择。这样做表明你可以问 pserve
要查看开发文件并在更改时重新加载服务器,请执行以下操作:
$VENV/bin/pserve development.ini --reload
这个 pserve
命令有许多其他选项和操作。但是,大多数工作都来自于项目的连接,正如您提供给的配置文件中所表达的那样。 pserve
. 让我们看看这个配置文件。
参见
参见: 这是什么 pserve 事情
配置 .ini
文件夹¶
早些时候 Quick Tour 我们第一次见到Pyramid的配置系统。在这一点上,我们用Python代码进行了所有配置。例如,在python代码中,为HTTP服务器选择的端口号就在那里。我们的cookiecutter已经把这个决定和更多的 development.ini
文件:
###
# app configuration
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
use = egg:hello_world
pyramid.reload_templates = true
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
pyramid.includes =
pyramid_debugtoolbar
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.
# debugtoolbar.hosts = 127.0.0.1 ::1
###
# wsgi server configuration
###
[server:main]
use = egg:waitress#main
listen = localhost:6543
###
# logging configuration
# https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
keys = root, hello_world
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = console
[logger_hello_world]
level = DEBUG
handlers =
qualname = hello_world
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s:%(lineno)s][%(threadName)s] %(message)s
让我们快速高层次地看看。首先 .ini
文件分为以下部分:
[app:main]
配置我们的wsgi应用程序[server:main]
保留我们的wsgi服务器设置之后的各个部分将配置我们的python日志记录系统
在这种配置中,我们有一些决定:
WSGI应用程序: 我们的wsgi应用程序在哪个包中?
use = egg:hello_world
在应用程序部分告诉配置要加载的应用程序。通过自动重新加载模板更容易开发: 在开发模式下,编辑jinja2模板时不需要重新启动服务器。
pyramid.reload_templates = true
设置此策略,这在生产中可能有所不同。Web服务器的选择:
use = egg:waitress#main
告诉pserve
使用waitress
服务器。接口:
listen = localhost:6543
告诉waitress
在端口6543上侦听IPv4和IPv6的所有接口。
另外, development.ini
由这个cookiecutter生成,连接了python的标准日志记录。例如,我们现在将在控制台中看到每个请求的日志,以及追溯信息。
更容易开发 debugtoolbar
¶
在介绍基础知识的同时,我们还想展示如何在开发和调试中提高生产力。例如,我们刚刚讨论了模板重新加载,之前我们展示了 --reload
用于重新加载应用程序。
pyramid_debugtoolbar
是一个流行的Pyramid加载项,它使您的浏览器中有几个工具可用。将它添加到项目中说明了配置的几个要点。
我们的cookiecutter pyramid-cookiecutter-starter
已将我们的包配置为包含附加组件 pyramid_debugtoolbar
在其 setup.py
:
11requires = [
12 'plaster_pastedeploy',
13 'pyramid',
14 'pyramid_jinja2',
15 'pyramid_debugtoolbar',
16 'waitress',
17]
它是在您以前运行时安装的:
$VENV/bin/pip install -e ".[testing]"
这个 pyramid_debugtoolbar
包是一个Pyramid附加组件,这意味着我们需要将它的配置包含到我们的Web应用程序中。cookiecutter已经为我们处理了 development.ini
使用 pyramid.includes
设施:
14pyramid.includes =
15 pyramid_debugtoolbar
现在,您将在浏览器窗口的右侧看到一个Pyramid徽标,单击后,将打开一个新窗口,提供调试信息。如果您的Web应用程序生成错误,您将在屏幕上看到一个很好的回溯。如果要禁用此工具栏,则无需更改代码:可以将其从 pyramid.includes
在相关 .ini
配置文件。
单元和功能测试以及 pytest
¶
Yikes!我们走了这么远,还没有讨论测试。这一点尤其令人震惊,因为Pyramid在发布之前就对全面的测试覆盖做出了深刻的承诺。
我们的 pyramid-cookiecutter-starter
已生成Cookiecuter conftest.py
, test_functional.py
,以及 test_views.py
中的模块。 tests
包中包含两个单元测试和两个功能测试。它还配置了 setup.py
对于测试要求,请执行以下操作: pytest
作为试跑者, WebTest
用于运行视图测试,并且 pytest-cov
向我们大喊未经测试的代码的工具:
19tests_require = [
20 'WebTest',
21 'pytest',
22 'pytest-cov',
23]
43 extras_require={
44 'testing': tests_require,
45 },
我们在运行命令时已经安装了测试需求 $VENV/bin/pip install -e ".[testing]"
. 我们现在可以运行所有测试:
$VENV/bin/pytest --cov --cov-report=term-missing
这将产生以下输出。
=========================== test session starts ===========================
platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
rootdir: /<somepath>/hello_world, configfile: pytest.ini, testpaths: hello_world, tests
plugins: cov-2.10.1
collected 4 items
tests/test_functional.py .. [ 50%]
tests/test_views.py .. [100%]
---------- coverage: platform darwin, python 3.9.0-final-0 -----------
Name Stmts Miss Cover Missing
-------------------------------------------------------------
hello_world/__init__.py 7 0 100%
hello_world/routes.py 3 0 100%
hello_world/views/__init__.py 0 0 100%
hello_world/views/default.py 4 0 100%
hello_world/views/notfound.py 5 0 100%
-------------------------------------------------------------
TOTAL 19 0 100%
======================== 4 passed in 0.65 seconds =========================
我们的测试通过了,它的覆盖范围是完整的。我们的测试是什么样子的?
1def test_root(testapp):
2 res = testapp.get('/', status=200)
3 assert b'Pyramid' in res.body
4
5def test_notfound(testapp):
6 res = testapp.get('/badurl', status=404)
7 assert res.status_code == 404
1from hello_world.views.default import my_view
2from hello_world.views.notfound import notfound_view
3
4
5def test_my_view(app_request):
6 info = my_view(app_request)
7 assert app_request.response.status_int == 200
8 assert info['project'] == 'hello_world'
9
10def test_notfound_view(app_request):
11 info = notfound_view(app_request)
12 assert app_request.response.status_int == 404
13 assert info == {}
Pyramid为测试编写提供助手,我们在测试设置和拆卸中使用它。我们的视图测试导入视图,发出一个虚拟请求,并查看视图是否返回我们期望的结果。我们的功能测试验证了从请求到web根目录的响应主体是否包含我们所期望的内容,以及向发出请求所需的响应代码 /badurl
结果在 404
.
Logging¶
了解我们的Web应用程序中发生了什么是很重要的。在开发中,我们可能需要收集一些输出。在生产中,我们可能需要检测其他人使用该站点时的情况。我们需要 Logging .
幸运的是,Pyramid使用普通的python方法进行日志记录。这个 development.ini
项目的文件有许多行,它们将日志配置为一些合理的默认值。然后,您会看到Pyramid发送的消息(例如,当一个新请求出现时)。
也许您想在代码中记录消息?在Python模块中,导入并设置中的日志记录 views/default.py
:
3import logging
4log = logging.getLogger(__name__)
现在,您可以在代码中记录消息:
7def my_view(request):
8 log.debug('Some Message')
这个日志 Some Message
在一 DEBUG
在您的 development.ini
. 是什么控制的?配置文件中的以下重点部分:
34[loggers]
35keys = root, hello_world
36
37[handlers]
38keys = console
39
40[formatters]
41keys = generic
42
43[logger_root]
44level = INFO
45handlers = console
46
47[logger_hello_world]
48level = DEBUG
49handlers =
50qualname = hello_world
我们的应用程序,一个名为 hello_world
,设置为记录器,并配置为在 DEBUG
或更高级别。当您访问http://localhost:6543时,您的控制台现在将显示:
2016-12-25 03:03:57,059 DEBUG [hello_world.views:8][waitress] Some Message
参见
参见: Quick Tutorial Logging 和 登录 .
会议¶
当人们使用您的Web应用程序时,他们经常执行需要保存半永久数据的任务。例如,购物车。这叫A session .
Pyramid对会话有基本的内置支持。第三方软件包,如 pyramid_redis_sessions
提供更丰富的会话支持。或者您可以创建自己的自定义会话引擎。让我们看看 built-in sessioning support . 在我们 __init__.py
我们首先导入所需的会话类型:
1from pyramid.config import Configurator
2from pyramid.session import SignedCookieSessionFactory
警告
如会话文档中所述,此示例实现不适用于具有安全含义的设置。
现在制作一个“工厂”并将其传递给 configurator 的 session_factory
论点:
9 config.include('.routes')
10 my_session_factory = SignedCookieSessionFactory('itsaseekreet')
11 config.set_session_factory(my_session_factory)
12 config.scan()
皮拉米德 request 对象现在有一个 session
可以在视图代码中使用的属性 views/default.py
:
7def my_view(request):
8 log.debug('Some Message')
9 session = request.session
10 if 'counter' in session:
11 session['counter'] += 1
12 else:
13 session['counter'] = 0
14 return {'project': 'hello_world'}
我们需要更新我们的jinja2模板 templates/mytemplate.jinja2
要在会话中显示计数器增量:
4<div class="content">
5 <h1><span class="font-semi-bold">Pyramid</span> <span class="smaller">Starter project</span></h1>
6 <p class="lead">Welcome to <span class="font-normal">{{project}}</span>, a Pyramid application generated by<br><span class="font-normal">Cookiecutter</span>.</p>
7 <p>Counter: {{ request.session.counter }}</p>
8</div>
参见
参见: Quick Tutorial Sessions , 会议 , Flash消息 , pyramid.session 和 pyramid_redis_sessions .
数据库¶
Web应用程序意味着数据。数据意味着数据库。通常是SQL数据库。SQL数据库通常意味着一个“ORM”(对象关系映射器),在Python中,ORM通常会带来巨大的质量 SQLAlchemy 这是一个python包,可以大大简化与数据库的工作。
Pyramid和sqlacalchemy是好朋友。包括cookiecutter!
cd ~
env/bin/cookiecutter gh:Pylons/pyramid-cookiecutter-starter --checkout main
If prompted for the first item, accept the default yes
按回车键。
You've cloned ~/.cookiecutters/pyramid-cookiecutter-starter before.
Is it okay to delete and re-clone it? [yes]: yes
project_name [Pyramid Scaffold]: sqla_demo
repo_name [sqla_demo]: sqla_demo
Select template_language:
1 - jinja2
2 - chameleon
3 - mako
Choose from 1, 2, 3 [1]: 1
Select backend:
1 - none
2 - sqlalchemy
3 - zodb
Choose from 1, 2, 3 [1]: 2
然后我们像以前一样运行以下命令。
# Change directory into your newly created project.
cd sqla_demo
# Create a new virtual environment...
python3 -m venv env
# ...where we upgrade packaging tools...
env/bin/pip install --upgrade pip setuptools
# ...and into which we install our project and its testing requirements.
env/bin/pip install -e ".[testing]"
# Reset our environment variable for a new virtual environment.
export VENV=~/sqla_demo/env
我们现在有了一个工作示例SQLAlchemy应用程序,并安装了所有依赖项。Alembic提供了一个从现有数据库迁移模型的示例和升级方法。让我们生成第一个修订版。
$VENV/bin/alembic -c development.ini revision --autogenerate -m "init"
现在让我们升级数据库模式。
$VENV/bin/alembic -c development.ini upgrade head
示例项目还提供了一个控制台脚本,用于将数据加载到SQLite数据库中。运行它,然后启动应用程序:
$VENV/bin/initialize_sqla_demo_db development.ini
$VENV/bin/pserve development.ini
ORM简化了数据库结构到编程语言的映射。SQLAlchemy对此映射使用“模型”。CookiCutter生成了一个示例模型:
11class MyModel(Base):
12 __tablename__ = 'models'
13 id = Column(Integer, primary_key=True)
14 name = Column(Text)
15 value = Column(Integer)
视图代码在Web请求和系统其余部分之间进行逻辑中介,然后借助sqlacalchemy,可以轻松获取数据:
8@view_config(route_name='home', renderer='sqla_demo:templates/mytemplate.jinja2')
9def my_view(request):
10 try:
11 query = request.dbsession.query(models.MyModel)
12 one = query.filter(models.MyModel.name == 'one').one()
13 except SQLAlchemyError:
14 return Response(db_err_msg, content_type='text/plain', status=500)
15 return {'one': one, 'project': 'sqla_demo'}
形式¶
开发人员对Web表单有很多意见,因此有许多用于Python的表单库。Pyramid不直接捆绑表单库,但是 变形 是一个流行的形式选择,连同它的相关 * colander * 模式系统。
例如,假设我们需要一个编辑wiki页面的表单。表单上应该有两个字段,一个是必需的标题,另一个是正文的富文本编辑器。使用deform,我们可以将其表示为一个colander模式:
class WikiPage(colander.MappingSchema):
title = colander.SchemaNode(colander.String())
body = colander.SchemaNode(
colander.String(),
widget=deform.widget.RichTextWidget()
)
有了这个功能,我们就可以呈现表单的HTML,也许可以使用现有页面的表单数据:
form = self.wiki_form.render()
我们要处理表单提交、验证和保存:
# Get the form data that was posted
controls = self.request.POST.items()
try:
# Validate and either raise a validation error
# or return deserialized data from widgets
appstruct = wiki_form.validate(controls)
except deform.ValidationFailure as e:
# Bail out and render form with errors
return dict(title=title, page=page, form=e.render())
# Change the content and redirect to the view
page['title'] = appstruct['title']
page['body'] = appstruct['body']
deform和colander为表单、小部件、模式和验证提供了非常灵活的组合。变形的最新版本还包括 retail mode 用于获取自定义窗体上的变形特征。
deform使用来自Twitter引导程序的有吸引力的CSS,以及更强大的选择、复选框、日期和时间小部件。
参见
参见: Quick Tutorial Forms , Deform 和 Colander .
结论¶
这个 Quick Tour 覆盖了很多。我们在Pyramid中引入了一长串概念,其中许多概念在Pyramid开发人员文档中进行了更全面的扩展。