SQLAlchemy

基本用法

您可以通过使用 alchemy 脚手架。检查 narrative docs 更多信息。

Alternatively, you can try to follow wiki tutorialblogr tutorial .

Using a Non-Global Session

有时不使用sqlachemy的线程范围会话是有利的(例如,当您需要在异步系统中使用Pyramid时)。谢天谢地,这么做很容易。您可以将会话工厂存储在应用程序的注册表中,并让调用会话工厂作为请求对象获取属性的副作用。会话对象的生存期将与请求的生存期相匹配。

我们要用 Configurator.add_request_method 将SQLAlchemy会话添加到请求对象和 Request.add_finished_callback to close said session.

注解

Configurator.add_request_method has been available since Pyramid 1.4. 你可以使用 Configurator.set_request_property for Pyramid 1.3.

我们假设你有 .ini 用文件 sqlalchemy. 正确指定数据库的设置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# __init__.py

from pyramid.config import Configurator
from sqlalchemy import engine_from_config
from sqlalchemy.orm import sessionmaker

def db(request):
    maker = request.registry.dbmaker
    session = maker()

    def cleanup(request):
        if request.exception is not None:
            session.rollback()
        else:
            session.commit()
        session.close()
    request.add_finished_callback(cleanup)

    return session


def main(global_config, **settings):
    config = Configurator(settings=settings)
    engine = engine_from_config(settings, prefix='sqlalchemy.')
    config.registry.dbmaker = sessionmaker(bind=engine)
    config.add_request_method(db, reify=True)

    # .. rest of configuration ...

The SQLAlchemy session is now available in view code as request.dbconfig.registry.dbmaker() .

Importing all SQLAlchemy Models

如果您使用粘贴器模板创建了一个 Pyramid 项目,那么默认情况下,您的sqlachemy模型将驻留在单个文件中。这只是惯例。如果您希望有一个sqlachemy模型目录而不是一个文件,那么当然可以创建一个包含模型模块的python包,替换 models.py 用一个文件 models 目录,它是一个python包(一个目录 __init__.py 在其中) Modifying Package Structure . However, due to the behavior of SQLAlchemy's "declarative" configuration mode, all modules which hold active SQLAlchemy models need to be imported before those models can successfully be used. So, if you use model classes with a declarative base, you need to figure out a way to get all your model modules imported to be able to use them in your application.

You might first create a models 目录,替换 models.py file, and within it a file named models/__init__.py . At that point, you can add a submodule named models/mymodel.py 持有一个 MyModel 模型类。这个 models/__init__.py 将定义声明性基类和全局 DBSession 对象,每个模型子模块(如 models/mymodel.py )需要导入。那么,您所需要的就是在其中添加每个子模块的导入 models/__init__.py .

但是,当您添加 models 将子模块导入语句打包到 models/__init__.py ,这将导致循环导入依赖项。这个 models/__init__.py 模块导入 mymodelmodels/mymodel.py 进口 models 包。下次尝试启动应用程序时,由于此循环依赖关系,它将失败并出现导入错误。

Pylons 1 solves this by creating a models/meta.py 模块,其中创建dbsession和声明性基对象。这个 models/__init__.py 文件和的每个子模块 models 进口 DBSessiondeclarative_base 从它。Whenever you create a .py 文件中 models 包,您需要将导入添加到 models/__init__.py . The main program imports the models 包,其副作用是确保所有模型类都已导入。你也可以这样做,它工作得很好。

However, you can alternately use config.scan() 因为它的副作用。使用 config.scan() allows you to avoid a circdep between models/__init__.pymodels/themodel.py without creating a special models/meta.py .

For example, if you do this in myapp/models/__init__.py ::

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session, sessionmaker

DBSession = scoped_session(sessionmaker())
Base = declarative_base()

def initialize_sql(engine):
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    Base.metadata.create_all(engine)

而这在 myapp/models/mymodel.py ::

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from myapp.models import Base
from sqlalchemy import Column
from sqlalchemy import Unicode
from sqlalchemy import Integer

class MyModel(Base):
    __tablename__ = 'models'
    id = Column(Integer, primary_key=True)
    name = Column(Unicode(255), unique=True)
    value = Column(Integer)

    def __init__(self, name, value):
        self.name = name
        self.value = value

而这在 myapp/__init__.py ::

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from sqlalchemy import engine_from_config

from myapp.models import initialize_sql

def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(settings=settings)
    config.scan('myapp.models') # the "important" line
    engine = engine_from_config(settings, 'sqlalchemy.')
    initialize_sql(engine)
    # other statements here
    config.add_handler('main', '/{action}',
                     'myapp.handlers:MyHandler')
    return config.make_wsgi_app()

config.scan('myapp.models') . config.scan 具有对给定的包名称执行递归导入的副作用。这种副作用确保 myapp.models 导入时不要求您在 models/__init__.py . It won't import any models that live outside the myapp.models package, however.