7:RDBMS根工厂¶
使用sqlAlchemy通过资源工厂提供持久的根资源。
背景¶
在 6:在ZODB中存储资源 我们使用了一个python对象数据库zodb来存储我们的资源树信息。ZODB在保持一个可以用于遍历的“位置感知”的图形结构方面非常有用。
Relational databases, though, aren't hierarchical. We can, however, use SQLAlchemy's adjacency list relationship 提供树状结构。我们将在接下来的两个步骤中进行此操作。
在第一步中,我们准备好了基础知识:sqlacalchemy、sqlite表、事务意识和根工厂,它们为我们提供了一个上下文。我们将使用 2:有立地根的基本导线测量 作为起点。
备注
此步骤假定您熟悉 19: Databases Using SQLAlchemy .
备注
遍历对sqlAlchemy邻接表关系和多态表继承的使用来自 Kotti 基于 Pyramid 的CMS,灵感来自plone。DanielNouri用各种技术和思想提出了SQL数据库中一流遍历的思想。科蒂无疑是寻找SQL中最现代的遍历层次结构方法的地方。
目标¶
在项目中引入sqlacalchemy和sqlite,包括事务意识。
提供存储在RDBMS中的根对象,并将其用作上下文。
步骤¶
我们将使用SiteRoot步骤作为起点:
$ cd ..; cp -r siteroot sqlroot; cd sqlroot
在中引入一些新的依赖项和控制台脚本
sqlroot/setup.py
:1from setuptools import setup 2 3requires = [ 4 'pyramid', 5 'pyramid_jinja2', 6 'pyramid_tm', 7 'sqlalchemy', 8 'zope.sqlalchemy', 9 'pyramid_debugtoolbar' 10] 11 12setup(name='tutorial', 13 install_requires=requires, 14 entry_points="""\ 15 [paste.app_factory] 16 main = tutorial:main 17 [console_scripts] 18 initialize_tutorial_db = tutorial.initialize_db:main 19 """, 20)
现在我们可以初始化我们的项目:
$ $VENV/bin/python setup.py develop
我们的配置文件位于
sqlroot/development.ini
wires together some new pieces:1[app:main] 2use = egg:tutorial 3pyramid.reload_templates = true 4pyramid.includes = 5 pyramid_debugtoolbar 6 pyramid_tm 7sqlalchemy.url = sqlite:///%(here)s/sqltutorial.sqlite 8 9[server:main] 10use = egg:pyramid#wsgiref 11host = 0.0.0.0 12port = 6543 13 14# Begin logging configuration 15 16[loggers] 17keys = root, tutorial, sqlalchemy 18 19[logger_tutorial] 20level = DEBUG 21handlers = 22qualname = tutorial 23 24[logger_sqlalchemy] 25level = INFO 26handlers = 27qualname = sqlalchemy.engine 28 29[handlers] 30keys = console 31 32[formatters] 33keys = generic 34 35[logger_root] 36level = INFO 37handlers = console 38 39[handler_console] 40class = StreamHandler 41args = (sys.stderr,) 42level = NOTSET 43formatter = generic 44 45[formatter_generic] 46format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s 47 48# End logging configuration
这个
setup.py
在处具有控制台脚本的入口点sqlroot/tutorial/initialize_db.py
, so let's add that script:1import os 2import sys 3import transaction 4 5from sqlalchemy import engine_from_config 6 7from pyramid.paster import ( 8 get_appsettings, 9 setup_logging, 10 ) 11 12from .models import ( 13 DBSession, 14 Root, 15 Base, 16 ) 17 18 19def usage(argv): 20 cmd = os.path.basename(argv[0]) 21 print('usage: %s <config_uri>\n' 22 '(example: "%s development.ini")' % (cmd, cmd)) 23 sys.exit(1) 24 25 26def main(argv=sys.argv): 27 if len(argv) != 2: 28 usage(argv) 29 config_uri = argv[1] 30 setup_logging(config_uri) 31 settings = get_appsettings(config_uri) 32 engine = engine_from_config(settings, 'sqlalchemy.') 33 DBSession.configure(bind=engine) 34 Base.metadata.create_all(engine) 35 36 with transaction.manager: 37 root = Root(title='My SQLTraversal Root') 38 DBSession.add(root)
我们的启动代码
sqlroot/tutorial/__init__.py
获取一些引导更改:1from pyramid.config import Configurator 2 3from sqlalchemy import engine_from_config 4 5from .models import ( 6 DBSession, 7 Base, 8 root_factory 9 ) 10 11 12def main(global_config, **settings): 13 engine = engine_from_config(settings, 'sqlalchemy.') 14 DBSession.configure(bind=engine) 15 Base.metadata.bind = engine 16 17 config = Configurator(settings=settings, 18 root_factory=root_factory) 19 config.include('pyramid_jinja2') 20 config.scan('.views') 21 return config.make_wsgi_app()
创造
sqlroot/tutorial/models.py
with our SQLAlchemy model for our persistent root:1from sqlalchemy import ( 2 Column, 3 Integer, 4 Text, 5 ) 6 7from sqlalchemy.ext.declarative import declarative_base 8 9from sqlalchemy.orm import ( 10 scoped_session, 11 sessionmaker, 12 ) 13 14from zope.sqlalchemy import ZopeTransactionExtension 15 16DBSession = scoped_session( 17 sessionmaker(extension=ZopeTransactionExtension())) 18Base = declarative_base() 19 20 21class Root(Base): 22 __name__ = '' 23 __parent__ = None 24 __tablename__ = 'root' 25 uid = Column(Integer, primary_key=True) 26 title = Column(Text, unique=True) 27 28 29def root_factory(request): 30 return DBSession.query(Root).one()
让我们运行这个控制台脚本,从而生成我们的数据库和表:
1$ $VENV/bin/initialize_tutorial_db development.ini 22013-09-29 15:42:23,564 INFO [sqlalchemy.engine.base.Engine][MainThread] PRAGMA table_info("root") 32013-09-29 15:42:23,565 INFO [sqlalchemy.engine.base.Engine][MainThread] () 42013-09-29 15:42:23,566 INFO [sqlalchemy.engine.base.Engine][MainThread] 5CREATE TABLE root ( 6 uid INTEGER NOT NULL, 7 title TEXT, 8 PRIMARY KEY (uid), 9 UNIQUE (title) 10) 11 12 132013-09-29 15:42:23,566 INFO [sqlalchemy.engine.base.Engine][MainThread] () 142013-09-29 15:42:23,569 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT 152013-09-29 15:42:23,572 INFO [sqlalchemy.engine.base.Engine][MainThread] BEGIN (implicit) 162013-09-29 15:42:23,573 INFO [sqlalchemy.engine.base.Engine][MainThread] INSERT INTO root (title) VALUES (?) 172013-09-29 15:42:23,573 INFO [sqlalchemy.engine.base.Engine][MainThread] ('My SQLAlchemy Root',) 182013-09-29 15:42:23,576 INFO [sqlalchemy.engine.base.Engine][MainThread] COMMIT
视图或模板中没有任何更改。
运行 Pyramid 应用程序时使用:
$ $VENV/bin/pserve development.ini --reload
在浏览器中打开http://localhost:6543/。
分析¶
我们执行与我们在中看到的相同类型的SQLAlchemy设置工作 19: Databases Using SQLAlchemy . 在这种情况下,根工厂从数据库返回一个对象。
这个 models.Root
实例是 context
context
.
这一点可以通过这样一个事实来说明:我们不必更改视图逻辑或模板。他们依赖于上下文。 Pyramid 找到了上下文并将其传递到我们的视图中。
Extra Credit¶
如果数据库没有
Root
与sqlAlchemy查询匹配?