pyramid框架
在这个由四部分组成的系列文章的第一篇文章中,比较了不同的Python Web框架,我解释了如何在Flask Web框架中创建“待办事项列表” Web应用程序。 在第二篇文章中,我将对Pyramid Web框架执行相同的任务。 未来的文章将关注Tornado和Django ; 在学习过程中,我将探索它们之间的更多差异。
金字塔自称为“从小处开始,从大处完成,保持完成的框架”,就像Flask一样,它只需很少的精力就可以启动并运行。 实际上,在构建此应用程序时,您会认识到许多相同的模式。 但是,两者之间的主要区别在于Pyramid附带了几个有用的实用程序,我将在后面简要介绍。
首先,创建一个虚拟环境并安装该软件包。
$ mkdir pyramid_todo
$ cd pyramid_todo
$ pipenv install --python 3.6
$ pipenv shell
(pyramid-someHash) $ pipenv install pyramid
与Flask一样,创建setup.py
文件以使您构建易于安装的Python发行版的应用程序很聪明。
# setup.py
from setuptools
import setup
, find_packages
requires
=
[
'pyramid'
,
'paster_pastedeploy'
,
'pyramid-ipython'
,
'waitress'
]
setup
(
name
=
'pyramid_todo'
,
version
=
'0.0'
,
description
=
'A To-Do List build with Pyramid'
,
author
=
'<Your name>'
,
author_email
=
'<Your email>'
,
keywords
=
'web pyramid pylons'
,
packages
= find_packages
(
)
,
include_package_data
=
True
,
install_requires
= requires
,
entry_points
=
{
'paste.app_factory' :
[
'main = todo:main'
,
]
}
)
entry_points
部分设置了其他服务可以使用的应用程序入口点。
这允许plaster_pastedeploy
包访问应用程序中用于构建应用程序对象并为其提供服务的main
功能。
(我会再圈出一点。)
在安装pyramid
,您还获得了一些特定于Pyramid的Shell命令。 主要需要注意的是pserve
和pshell
。 pserve
将采用指定为参数的INI样式的配置文件,并在本地为应用程序提供服务。 pshell
还将一个配置文件作为参数,但是它不提供服务,而是打开了一个Python外壳程序,该外壳程序知道应用程序及其内部配置。
配置文件非常重要,因此值得仔细研究。 金字塔可以从环境变量或配置文件中进行配置。 为了避免在哪里出现太多混乱,在本教程中,您将大部分配置写入配置文件中,而在虚拟环境中仅设置了一些敏感的配置参数。
创建一个名为config.ini
的文件
[ app:main ]
use
=
egg:todo
pyramid.default_locale_name
=
en
[ server:main ]
use
=
egg:waitress#main
listen
=
localhost:6543
这说明了两点:
todo
包中的main
功能 waitress
软件包,并在localhost端口6543上提供服务 在为应用程序提供服务并从事开发工作时,它有助于设置日志记录,以便您查看正在发生的事情。 以下配置将处理应用程序的日志记录:
# continuing on...
[ loggers ]
keys
=
root, todo
[ handlers ]
keys
=
console
[ formatters ]
keys
=
generic
[ logger_root ]
level
=
INFO
handlers
=
console
[ logger_todo ]
level
=
DEBUG
handlers
=
qualname
=
todo
[ 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
简而言之,此配置要求将与应用程序有关的所有事情记录到控制台。 如果您希望减少输出,请将日志记录级别设置为WARN
这样只有在出现问题时才会触发消息。
由于Pyramid适用于不断增长的应用程序,因此请规划一个可以支持这种增长的文件结构。 当然,可以根据需要构建Web应用程序。 通常,您要涵盖的概念块将包含:
鉴于以上所述,文件结构如下所示:
setup.
py
config.
ini
todo/
__init__ .
py
models.
py
routes.
py
views.
py
scripts/
与Flask的app
对象非常相似,Pyramid具有自己的中央配置。 它来自其config
模块,被称为Configurator
对象。 该对象将处理从路由配置到指向模型和视图存在的所有内容。 所有这些操作都是在__init__.py
文件中名为todo
的内部目录中完成的。
# todo/__init__.py
from pyramid.
config
import Configurator
def main
( global_config
, **settings
) :
"""Returns a Pyramid WSGI application."""
config
= Configurator
( settings
= settings
)
config.
scan
(
)
return config.
make_wsgi_app
(
)
main
功能从您的环境中查找一些全局配置,以及在运行应用程序时通过特定配置文件提供的所有设置。 它接受这些设置,并使用它们来构建Configurator
对象的实例,该对象(出于所有目的和目的)是应用程序的工厂。 最后, config.scan()
查找您要附加到应用程序的所有标记为金字塔视图的视图。
哇,要配置的东西很多。
现在已经完成了大部分配置,您可以开始向应用程序添加功能。 功能以外部客户端可以访问的URL路由的形式出现,然后映射到Python可以运行的功能。
对于金字塔,必须以某种方式,形状或形式将所有功能添加到Configurator
中。 例如,假设您要构建与Flask构建的相同的简单hello_world
视图,并映射到/
的路由。 使用Pyramid,您可以使用.add_route()
方法在Configurator
器中注册/
路由。 此方法将要添加的路由的名称以及访问该路由必须匹配的实际模式作为参数。 对于这种情况,请将以下内容添加到您的Configurator
:
config.add_route('home', '/')
在创建视图并将其附加到该路由之前,进入您应用程序的路径一直处于打开状态并且是单独存在的。 添加视图时,请确保将request
对象包括在参数列表中。 每个Pyramid视图都必须将request
对象作为其第一个参数,因为这是Pyramid调用该视图时作为第一个参数传递的内容。
金字塔视图与Flask共享的一个相似之处是,您可以使用装饰器将函数标记为视图。 具体而言, @view_config
从装饰pyramid.view
。
在views.py
,构建您想在世界上看到的视图。
from pyramid.
view
import view_config
@ view_config
( route_name
=
"hello"
, renderer
=
"string"
)
def hello_world
( request
) :
"""Print 'Hello, world!' as the response body."""
return
'Hello, world!'
使用@view_config
装饰器,您至少必须指定将映射到该特定视图的路由的名称。 如果需要,您可以将view_config
装饰器彼此堆叠以映射到多个路由,但是必须至少有一个连接视图,并且每个视图都必须包含路由的名称。 [注意:“连接视图”是否正确表达?]
另一个参数renderer
是可选的,但不是真的 。 如果不指定渲染器,则必须使用pyramid.response
的Response
对象故意构造要发送回客户端的HTTP响应。 通过将renderer
指定为字符串,Pyramid知道接受此函数返回的任何内容,并将其包装在MIME类型为text/plain
同一Response
对象中。 默认情况下,Pyramid允许您使用string
和json
作为渲染器。 如果由于希望Pyramid也生成HTML而将模板引擎附加到应用程序,则可以直接将HTML模板指向渲染器。
第一个视图完成。 这是带有附加路由的__init__.py
现在的样子。
# in __init__.py
from pyramid.
config
import Configurator
def main
( global_config
, **settings
) :
"""Returns a Pyramid WSGI application."""
config
= Configurator
( settings
= settings
)
config.
add_route
(
'hello'
,
'/'
)
config.
scan
(
)
return config.
make_wsgi_app
(
)
壮观! 到达这里并非易事,但是现在您已经完成设置,可以以大大降低的难度添加功能。
目前,该应用程序只有一条路由,但是很容易看到一个大型应用程序可以有数十甚至数百条路由。 将它们全部包含在与中央配置相同的main
功能中并不是最好的主意,因为这会变得很混乱。 值得庆幸的是,包含对应用程序进行一些调整的路由是相当容易的。
一 :在routes.py
文件,创建一个名为函数includeme
(是的,它必须真正被命名此),其采用一个配置对象作为参数。
# in routes.py
def includeme
( config
) :
"""Include these routes within the application."""
二 :将config.add_route
方法调用从__init__.py
移到includeme
函数中:
def includeme
( config
) :
"""Include these routes within the application."""
config.
add_route
(
'hello'
,
'/'
)
三 :警告配置器您需要将此routes.py
文件作为其配置的一部分。 由于它与__init__.py
位于同一目录中,因此您可以将此文件的导入路径指定为.routes
。
# in __init__.py
from pyramid.
config
import Configurator
def main
( global_config
, **settings
) :
"""Returns a Pyramid WSGI application."""
config
= Configurator
( settings
= settings
)
config.
include
(
'.routes'
)
config.
scan
(
)
return config.
make_wsgi_app
(
)
与Flask一样,您将需要通过连接数据库来保留数据。 金字塔将直接利用SQLAlchemy ,而不是使用专门定制的软件包。
首先,将简单的部分排除在外。 psycopg2
和sqlalchemy
与Postgres数据库进行对话并管理模型,因此将它们添加到setup.py
。
# in setup.py
requires
=
[
'pyramid'
,
'pyramid-ipython'
,
'waitress'
,
'sqlalchemy'
,
'psycopg2'
]
# blah blah other code
现在,您可以决定如何添加数据库的URL。 这里没有错误的答案; 您将做什么取决于您正在构建的应用程序以及代码库的公开程度。
通过将数据库URL硬编码到config.ini
文件中,第一个选项将把尽可能多的配置保留在一个地方。 一个缺点是,这会对具有公共代码库的应用程序造成安全风险。 可以查看代码库的任何人都可以看到完整的数据库URL,包括用户名,密码,数据库名称和端口。 另一个是可维护性。 如果需要更改环境或应用程序的数据库位置,则必须直接修改config.ini
文件。 要么,要么您必须为每个新环境维护一个配置文件,这增加了应用程序不连续和错误的可能性。 如果选择此选项 ,请在[app:main]
标题下修改config.ini
文件以包括此键值对:
sqlalchemy.url = postgres://localhost:5432/pyramid_todo
第二个选项指定创建Configurator
时数据库URL的位置,指向一个环境变量,其值可以根据您所使用的环境进行设置。 缺点之一是您需要进一步破坏配置,其中一些位于config.ini
文件中,而某些则直接在Python代码库中。 另一个缺点是,当您需要在应用程序中其他任何地方(例如,在数据库管理脚本中)使用数据库URL时,必须在第二次引用中对该同一个环境变量进行编码(或在一个位置设置该变量,然后从该位置导入)。 如果选择此选项 ,请添加以下内容:
# in __init__.py
import
os
from pyramid.
config
import Configurator
SQLALCHEMY_URL
=
os .
environ .
get
(
'DATABASE_URL'
,
''
)
def main
( global_config
, **settings
) :
"""Returns a Pyramid WSGI application."""
settings
[
'sqlalchemy.url'
]
= SQLALCHEMY_URL
# <-- important!
config
= Configurator
( settings
= settings
)
config.
include
(
'.routes'
)
config.
scan
(
)
return config.
make_wsgi_app
(
)
好,现在您有了一个数据库。 现在,您需要Task
和User
对象。
由于金字塔直接使用SQLAlchemy,因此金字塔在生成对象方面与Flash有所不同。 首先,您要构造的每个对象都必须继承自SQLAlchemy的声明性基类 。 它将跟踪继承自它的所有内容,从而简化数据库管理。
# in models.py
from sqlalchemy.
ext .
declarative
import declarative_base
Base
= declarative_base
(
)
class Task
( Base
) :
pass
class User
( Base
) :
pass
列,这些列的数据类型以及模型关系的声明方式与Flask相同,尽管它们将直接从SQLAlchemy导入,而不是从某些预先构造的db
对象中导入。 其他一切都一样。
# in models.py
from
datetime
import
datetime
import secrets
from sqlalchemy
import
(
Column
, Unicode
, Integer
, DateTime
, Boolean
, relationship
)
from sqlalchemy.
ext .
declarative
import declarative_base
Base
= declarative_base
(
)
class Task
( Base
) :
"""Tasks for the To Do list."""
id
= Column
( Integer
, primary_key
=
True
)
name
= Column
( Unicode
, nullable
=
False
)
note
= Column
( Unicode
)
creation_date
= Column
( DateTime
, nullable
=
False
)
due_date
= Column
( DateTime
)
completed
= Column
( Boolean
, default
=
False
)
user_id
= Column
( Integer
, ForeignKey
(
'user.id'
)
, nullable
=
False
)
user
= relationship
(
"user"
, back_populates
=
"tasks"
)
def
__init__
(
self
, *args
, **kwargs
) :
"""On construction, set date of creation."""
super
(
) .
__init__
( *args
, **kwargs
)
self .
creation_date
=
datetime .
now
(
)
class User
( Base
) :
"""The User object that owns tasks."""
id
= Column
( Integer
, primary_key
=
True
)
username
= Column
( Unicode
, nullable
=
False
)
email
= Column
( Unicode
, nullable
=
False
)
password
= Column
( Unicode
, nullable
=
False
)
date_joined
= Column
( DateTime
, nullable
=
False
)
token
= Column
( Unicode
, nullable
=
False
)
tasks
= relationship
(
"Task"
, back_populates
=
"user"
)
def
__init__
(
self
, *args
, **kwargs
) :
"""On construction, set date of creation."""
super
(
) .
__init__
( *args
, **kwargs
)
self .
date_joined
=
datetime .
now
(
)
self .
token
= secrets.
token_urlsafe
(
64
)
请注意,有没有config.include
线路models.py
的任何地方,因为它是没有必要的。 仅当需要更改应用程序配置的某些部分时,才需要config.include
行。 这仅创建了两个对象,它们继承自SQLAlchemy提供给我们的某些Base
类。
现在已经完成了模型,您可以编写脚本来与数据库对话并对其进行初始化。 在scripts
目录中,创建两个文件: __init__.py
和initializedb.py
。 第一种是简单地将scripts
目录转换为Python包。 第二个是数据库管理所需的脚本。
initializedb.py
需要一个函数来设置数据库中的必要表。 与Flask一样,此脚本必须知道Base
对象,该对象的元数据跟踪从其继承的每个类。 需要数据库URL指向和修改其表。
这样,此数据库初始化脚本将起作用:
# initializedb.py
from sqlalchemy
import engine_from_config
from todo
import SQLALCHEMY_URL
from todo.
models
import Base
def main
(
) :
settings
=
{
'sqlalchemy.url' : SQLALCHEMY_URL
}
engine
= engine_from_config
( settings
, prefix
=
'sqlalchemy.'
)
if
bool
(
os .
environ .
get
(
'DEBUG'
,
''
)
) :
Base.
metadata .
drop_all
( engine
)
Base.
metadata .
create_all
( engine
)
重要说明:仅当将数据库URL作为环境变量包含在todo/__init__.py
(上面的第二个选项)中时,此方法才有效。 如果数据库URL存储在配置文件中,则必须包括几行内容来读取该文件。 它看起来像这样:
# alternate initializedb.py
from pyramid.
paster
import get_appsettings
from pyramid.
scripts .
common
import parse_vars
from sqlalchemy
import engine_from_config
import
sys
from todo.
models
import Base
def main
(
) :
config_uri
=
sys .
argv
[
1
]
options
= parse_vars
(
sys .
argv
[
2 :
]
)
settings
= get_appsettings
( config_uri
, options
= options
)
engine
= engine_from_config
( settings
, prefix
=
'sqlalchemy.'
)
if
bool
(
os .
environ .
get
(
'DEBUG'
,
''
)
) :
Base.
metadata .
drop_all
( engine
)
Base.
metadata .
create_all
( engine
)
无论哪种方式,都在setup.py
中添加一个控制台脚本,该脚本将访问并运行此功能。
# bottom of setup.py
setup
(
# ... other stuff
entry_points
=
{
'paste.app_factory' :
[
'main = todo:main'
,
]
,
'console_scripts' :
[
'initdb = todo.scripts.initializedb:main'
,
]
,
}
)
安装此软件包后,您将可以访问名为initdb
的新控制台脚本,该脚本将在数据库中构造表。 如果数据库URL存储在配置文件中,则在调用命令时必须包括该文件的路径。 看起来像$ initdb /path/to/config.ini
。
好的,这就是它的深处。 让我们谈谈交易 。 抽象而言,“事务”是对现有数据库所做的任何更改。 与Flask一样,事务的持久性不早于提交时。 如果进行了尚未提交的更改,并且您不希望这些更改发生(过程中可能引发了错误),则可以回滚事务并中止这些更改。
在Python中, 事务包允许您将事务作为对象与之交互,从而可以将多个更改汇总到一个提交中。 transaction
提供了事务管理器 ,这些事务管理器为应用程序提供了一种直接的,线程感知的方式来处理事务,因此您只需考虑要更改的内容。 pyramid_tm
软件包将使事务管理器脱离transaction
并以适合Pyramid的请求-响应周期的方式将其连接起来,将事务管理器附加到每个传入请求。
通常,使用Pyramid时,当访问到视图的路由映射并调用视图函数时,将填充request
对象。 每个视图功能将有 一个 request
对象 一起工作 。 但是,Pyramid允许您修改其配置,以将所需的内容添加到request
对象。 您可以使用要添加到request
的事务管理器来创建每个请求的会话,并将该会话添加到请求中。
是的,为什么这很重要?
通过将事务管理的会话附加到request
对象, 当视图完成对请求的处理时,对数据库会话所做的任何更改都将被提交,而无需您显式提交 。 这就是所有这些概念在代码中的样子。
# __init__.py
import
os
from pyramid.
config
import Configurator
from sqlalchemy
import engine_from_config
from sqlalchemy.
orm
import sessionmaker
import zope.
sqlalchemy
SQLALCHEMY_URL
=
os .
environ .
get
(
'DATABASE_URL'
,
''
)
def get_session_factory
( engine
) :
"""Return a generator of database session objects."""
factory
= sessionmaker
(
)
factory.
configure
( bind
= engine
)
return factory
def get_tm_session
( session_factory
, transaction_manager
) :
"""Build a session and register it as a transaction-managed session."""
dbsession
= session_factory
(
)
zope.
sqlalchemy .
register
( dbsession
, transaction_manager
= transaction_manager
)
return dbsession
def main
( global_config
, **settings
) :
"""Returns a Pyramid WSGI application."""
settings
[
'sqlalchemy.url'
]
= SQLALCHEMY_URL
settings
[
'tm.manager_hook'
]
=
'pyramid_tm.explicit_manager'
config
= Configurator
( settings
= settings
)
config.
include
(
'.routes'
)
config.
include
(
'pyramid_tm'
)
session_factory
= get_session_factory
( engine_from_config
( settings
, prefix
=
'sqlalchemy.'
)
)
config.
registry
[
'dbsession_factory'
]
= session_factory
config.
add_request_method
(
lambda request: get_tm_session
( session_factory
, request.
tm
)
,
'dbsession'
,
reify
=
True
)
config.
scan
(
)
return config.
make_wsgi_app
(
)
看起来很多,但这只是上面所解释的,而且还向request
对象添加了一个名为request.dbsession
的属性。
这里包括一些新软件包,因此请使用这些软件包更新setup.py
。
# in setup.py
requires
=
[
'pyramid'
,
'pyramid-ipython'
,
'waitress'
,
'sqlalchemy'
,
'psycopg2'
,
'pyramid_tm'
,
'transaction'
,
'zope.sqlalchemy'
]
# blah blah other stuff
您需要制作一些真实的视图来处理数据库中的数据以及映射到它们的路由。
从路线开始。 您创建了routes.py
文件来处理您的路线,但是除了基本的/
路线之外,并没有做其他事情。 让我们修复它。
# routes.py
def includeme
( config
) :
config.
add_route
(
'info'
,
'/api/v1/'
)
config.
add_route
(
'register'
,
'/api/v1/accounts'
)
config.
add_route
(
'profile_detail'
,
'/api/v1/accounts/{username}'
)
config.
add_route
(
'login'
,
'/api/v1/accounts/login'
)
config.
add_route
(
'logout'
,
'/api/v1/accounts/logout'
)
config.
add_route
(
'tasks'
,
'/api/v1/accounts/{username}/tasks'
)
config.
add_route
(
'task_detail'
,
'/api/v1/accounts/{username}/tasks/{id}'
)
现在,它不仅具有/api/v1/accounts
类的静态URL,而且还可以处理/api/v1/accounts/{username}/tasks/{id}
等一些可变URL,其中URL中的任何变量都将被包围大括号。
要创建视图以在您的应用程序中创建单个任务(例如在Flash示例中),可以使用@view_config
装饰器以确保它仅接收传入的POST
请求,并检查Pyramid如何处理来自客户端的数据。
看一下代码,然后检查一下它与Flask版本的区别。
# in views.py
from
datetime
import
datetime
from pyramid.
view
import view_config
from todo.
models
import Task
, User
INCOMING_DATE_FMT
=
'%d/%m/%Y %H:%M:%S'
@ view_config
( route_name
=
"tasks"
, request_method
=
"POST"
, renderer
=
'json'
)
def create_task
( request
) :
"""Create a task for one user."""
response
= request.
response
response.
headers .
extend
(
{
'Content-Type' :
'application/json'
}
)
user
= request.
dbsession .
query
( User
) .
filter_by
( username
= request.
matchdict
[
'username'
]
) .
first
(
)
if
user :
due_date
= request.
json
[
'due_date'
]
task
= Task
(
name
= request.
json
[
'name'
]
,
note
= request.
json
[
'note'
]
,
due_date
=
datetime .
strptime
( due_date
, INCOMING_DATE_FMT
)
if due_date
else
None
,
completed
=
bool
( request.
json
[
'completed'
]
)
,
user_id
=
user .
id
)
request.
dbsession .
add
( task
)
response.
status_code
=
201
return
{
'msg' :
'posted'
}
首先,在@view_config
装饰器上注意,您希望此视图处理的唯一请求类型是“ POST”请求。 如果要指定一种请求类型或一组请求,请提供注释请求的字符串或此类字符串的元组/列表。
response
= request.
response
response.
headers .
extend
(
{
'Content-Type' :
'application/json'
}
)
# ...other code...
response.
status_code
=
201
发送到客户端的HTTP响应是基于request.response
生成的。 通常,您不必担心该对象。 它只会产生格式正确的HTTP响应,而您永远不会知道它们之间的区别。 但是,由于要执行特定的操作,例如修改响应的状态代码和标头,因此需要访问该响应及其方法/属性。
与Flask不同,您不需要仅因为路由URL中包含变量而修改视图函数参数列表。 取而代之的是,只要路径URL中存在变量,便会在request
的matchdict
属性中收集该matchdict
。 它在那里将作为键值对存在,其中键将是变量(例如,“用户名”),值将是路由中指定的任何值(例如,“ bobdobson”)。 无论通过路由URL传递什么值,它始终会在matchdict
显示为字符串。 因此,当您要从传入的请求URL中提取用户名时,请使用request.matchdict['username']
user = request.dbsession.query(User).filter_by(username=request.matchdict['username']).first()
使用sqlalchemy
直接查询对象与flask-sqlalchemy
软件包所允许的对象有很大不同。 回想一下,当您使用flask-sqlalchemy
构建模型时,这些模型是从db.Model
对象继承的。 该db
对象已经包含与数据库的连接 ,因此该连接可以执行简单的操作,如User.query.all()
。
这个简单的界面在这里不存在,因为Pyramid应用程序中的模型继承自Base
,而Base
是从declarative_base()
生成的,直接来自sqlalchemy
包。 它没有直接知道将要访问的数据库。 该意识是通过应用程序的中央配置作为dbsession
属性附加到request
对象的。 这是上面做的代码:
config.
add_request_method
(
lambda request: get_tm_session
( session_factory
, request.
tm
)
,
'dbsession'
,
reify
=
True
)
综上所述, 无论何时要查询或修改数据库,都必须 遍历 request.dbsession
。 在这种情况下,您想通过使用特定用户的用户名作为其标识符来查询“用户”表。 这样,将User
对象作为.query
方法的参数提供,然后从那里完成常规SQLAlchemy操作。
这种查询数据库方式的有趣之处在于,您可以查询多个对象或一种类型的对象的列表。 您可以查询:
request.dbsession.query(User.username)
将查询用户名 request.dbsession.query(User.username, User.date_joined)
request.dbsession.query(User, Task)
与传入请求一起发送的数据将在request.json
字典中找到。
最后一个主要区别是,由于将会话活动的提交附加到Pyramid的请求-响应周期所必需的所有机械手段,因此不必在视图末尾调用request.dbsession.commit()
。 这很方便,但是要前进是一件事。 如果要在数据库中编辑现有对象,而不是在数据库中添加新对象,则不能使用request.dbsession.commit()
。 金字塔将引发错误,并说“事务正在由事务管理器处理提交行为,因此您不能自己调用它”。 而且,如果您不做类似于提交更改的操作,则更改将不会生效。
解决方案是使用request.dbsession.flush()
。 .flush()
的工作是向数据库发出信号,表明已进行了一些更改,需要在下一次提交中包括这些更改。
至此,您已经设置了金字塔的大部分重要部分,类似于您在第一部分中用Flask构建的部分。 应用程序还有很多,但是这里有很多肉。 其他视图函数将采用类似的格式,当然,始终存在安全性问题(Pyramid内置了该功能!)。
我在Pyramid应用程序设置中看到的主要区别之一是,它与Flask相比,配置步骤更加紧张。 我分解了这些配置步骤,以详细说明构建Pyramid应用程序时发生的情况。 然而,自从我开始编程以来就表现出所有类似的感觉是不明智的。 我对Pyramid框架的初次体验是使用Pyramid 1.7及其pcreate
脚手架系统,该系统构建了大多数必需的配置,因此您要做的就是考虑要构建的功能。
作为金字塔1.8, pcreate
已经被弃用,取而代之的18.11 ,有效地做同样的事情。 区别在于它是由其他人维护的,并且存在cookiecutter模板,而不仅仅是金字塔项目。 既然我们已经遍历了Pyramid项目的各个组成部分,那么当 cookiecutter 模板可用 时 , 我再也不会支持从头开始构建Pyramid项目 。 如果不需要,为什么还要努力? 实际上, 金字塔形饼干炼金术模板将完成我在这里编写的大部分内容(还有更多)。 它实际上与我初次学习金字塔时使用的pcreate
支架相似。
在PyCon Cleveland 2018上了解更多Python。
pyramid框架