From a6d08e1ad8c8bbcc7e14eabf06e26507e636d538 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 3 Feb 2016 23:46:40 -0600 Subject: improve the models api/usage and add a lot of comments --- pyramid/scaffolds/alchemy/+package+/__init__.py | 2 +- .../scaffolds/alchemy/+package+/models/__init__.py | 71 +++++++++++++++++++++- pyramid/scaffolds/alchemy/+package+/models/meta.py | 33 ---------- .../scaffolds/alchemy/+package+/models/mymodel.py | 3 +- .../alchemy/+package+/scripts/initializedb.py | 9 +-- pyramid/scaffolds/alchemy/+package+/tests.py_tmpl | 8 +-- 6 files changed, 80 insertions(+), 46 deletions(-) diff --git a/pyramid/scaffolds/alchemy/+package+/__init__.py b/pyramid/scaffolds/alchemy/+package+/__init__.py index 7994bbfa8..17763812a 100644 --- a/pyramid/scaffolds/alchemy/+package+/__init__.py +++ b/pyramid/scaffolds/alchemy/+package+/__init__.py @@ -6,7 +6,7 @@ def main(global_config, **settings): """ config = Configurator(settings=settings) config.include('pyramid_jinja2') - config.include('.models.meta') + config.include('.models') config.add_static_view('static', 'static', cache_max_age=3600) config.add_route('home', '/') config.scan() diff --git a/pyramid/scaffolds/alchemy/+package+/models/__init__.py b/pyramid/scaffolds/alchemy/+package+/models/__init__.py index 6ffc10a78..e55689f2c 100644 --- a/pyramid/scaffolds/alchemy/+package+/models/__init__.py +++ b/pyramid/scaffolds/alchemy/+package+/models/__init__.py @@ -1,7 +1,72 @@ +from sqlalchemy import engine_from_config +from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import configure_mappers -# import all models classes here for sqlalchemy mappers -# to pick up +import zope.sqlalchemy + +# import or define all models here to ensure they are attached to the +# Base.metadata prior to any initialization routines from .mymodel import MyModel # flake8: noqa -# run configure mappers to ensure we avoid any race conditions +# run configure_mappers after defining all of the models to ensure +# all relationships can be setup configure_mappers() + + +def get_engine(settings, prefix='sqlalchemy.'): + return engine_from_config(settings, prefix) + + +def get_sessionmaker(engine): + dbmaker = sessionmaker() + dbmaker.configure(bind=engine) + return dbmaker + + +def get_tm_session(dbmaker, transaction_manager): + """ + Get a ``sqlalchemy.orm.Session`` instance backed by a transaction. + + This function will hook the session to the transaction manager which + will take care of committing any changes. + + - When using pyramid_tm it will automatically be committed or aborted + depending on whether an exception is raised. + + - When using scripts you should wrap the session in a manager yourself. + For example:: + + import transaction + + engine = get_engine(settings) + dbmaker = get_sessionmaker(engine) + with transaction.manager: + dbsession = get_tm_session(dbmaker, transaction.manager) + + """ + dbsession = dbmaker() + zope.sqlalchemy.register( + dbsession, transaction_manager=transaction_manager) + return dbsession + + +def includeme(config): + """ + Initialize the model for a Pyramid app. + + Activate this setup using ``config.include('{{package}}.models')``. + + """ + settings = config.get_settings() + + # use pyramid_tm to hook the transaction lifecycle to the request + config.include('pyramid_tm') + + dbmaker = get_sessionmaker(get_engine(settings)) + + # make request.dbsession available for use in Pyramid + config.add_request_method( + # r.tm is the transaction manager used by pyramid_tm + lambda r: get_tm_session(dbmaker, r.tm), + 'dbsession', + reify=True + ) diff --git a/pyramid/scaffolds/alchemy/+package+/models/meta.py b/pyramid/scaffolds/alchemy/+package+/models/meta.py index 80ececd8c..fc3e8f1dd 100644 --- a/pyramid/scaffolds/alchemy/+package+/models/meta.py +++ b/pyramid/scaffolds/alchemy/+package+/models/meta.py @@ -1,8 +1,5 @@ -from sqlalchemy import engine_from_config from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker from sqlalchemy.schema import MetaData -import zope.sqlalchemy # Recommended naming convention used by Alembic, as various different database # providers will autogenerate vastly different names making migrations more @@ -17,33 +14,3 @@ NAMING_CONVENTION = { metadata = MetaData(naming_convention=NAMING_CONVENTION) Base = declarative_base(metadata=metadata) - - -def includeme(config): - settings = config.get_settings() - dbmaker = get_dbmaker(get_engine(settings)) - - config.add_request_method( - lambda r: get_session(r.tm, dbmaker), - 'dbsession', - reify=True - ) - - config.include('pyramid_tm') - - -def get_session(transaction_manager, dbmaker): - dbsession = dbmaker() - zope.sqlalchemy.register(dbsession, - transaction_manager=transaction_manager) - return dbsession - - -def get_engine(settings, prefix='sqlalchemy.'): - return engine_from_config(settings, prefix) - - -def get_dbmaker(engine): - dbmaker = sessionmaker() - dbmaker.configure(bind=engine) - return dbmaker diff --git a/pyramid/scaffolds/alchemy/+package+/models/mymodel.py b/pyramid/scaffolds/alchemy/+package+/models/mymodel.py index 5a2b5890c..d65a01a42 100644 --- a/pyramid/scaffolds/alchemy/+package+/models/mymodel.py +++ b/pyramid/scaffolds/alchemy/+package+/models/mymodel.py @@ -1,4 +1,3 @@ -from .meta import Base from sqlalchemy import ( Column, Index, @@ -6,6 +5,8 @@ from sqlalchemy import ( Text, ) +from .meta import Base + class MyModel(Base): __tablename__ = 'models' diff --git a/pyramid/scaffolds/alchemy/+package+/scripts/initializedb.py b/pyramid/scaffolds/alchemy/+package+/scripts/initializedb.py index 0b2a42c59..13d4e543e 100644 --- a/pyramid/scaffolds/alchemy/+package+/scripts/initializedb.py +++ b/pyramid/scaffolds/alchemy/+package+/scripts/initializedb.py @@ -11,9 +11,9 @@ from pyramid.scripts.common import parse_vars from ..models import ( Base, - get_session, get_engine, - get_dbmaker, + get_sessionmaker, + get_tm_session, ) from ..models import MyModel @@ -36,9 +36,10 @@ def main(argv=sys.argv): engine = get_engine(settings) Base.metadata.create_all(engine) - dbmaker = get_dbmaker(engine) - dbsession = get_session(transaction.manager, dbmaker) + dbmaker = get_sessionmaker(engine) with transaction.manager: + dbsession = get_tm_session(dbmaker, transaction.manager) + model = MyModel(name='one', value=1) dbsession.add(model) diff --git a/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl b/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl index 01f2cb4cc..4eecaf33c 100644 --- a/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl +++ b/pyramid/scaffolds/alchemy/+package+/tests.py_tmpl @@ -17,15 +17,15 @@ class BaseTest(unittest.TestCase): settings = self.config.get_settings() from .models import ( - get_session, get_engine, - get_dbmaker, + get_sessionmaker, + get_tm_session, ) self.engine = get_engine(settings) - dbmaker = get_dbmaker(self.engine) + dbmaker = get_sessionmaker(self.engine) - self.session = get_session(transaction.manager, dbmaker) + self.session = get_tm_session(dbmaker, transaction.manager) def init_database(self): from .models import Base -- cgit v1.2.3