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中的根对象,并将其用作上下文。

步骤

  1. 我们将使用SiteRoot步骤作为起点:

    $ cd ..; cp -r siteroot sqlroot; cd sqlroot
    
  2. 在中引入一些新的依赖项和控制台脚本 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)
    
  3. 现在我们可以初始化我们的项目:

    $ $VENV/bin/python setup.py develop
    
  4. 我们的配置文件位于 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
    
  5. 这个 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)
    
  6. 我们的启动代码 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()
    
  7. 创造 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()
    
  8. 让我们运行这个控制台脚本,从而生成我们的数据库和表:

     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
    
  9. 视图或模板中没有任何更改。

  10. 运行 Pyramid 应用程序时使用:

    $ $VENV/bin/pserve development.ini --reload
    
  11. 在浏览器中打开http://localhost:6543/。

分析

我们执行与我们在中看到的相同类型的SQLAlchemy设置工作 19: Databases Using SQLAlchemy . 在这种情况下,根工厂从数据库返回一个对象。

这个 models.Root 实例是 context context .

这一点可以通过这样一个事实来说明:我们不必更改视图逻辑或模板。他们依赖于上下文。 Pyramid 找到了上下文并将其传递到我们的视图中。

Extra Credit

  1. 如果数据库没有 Root 与sqlAlchemy查询匹配?