This is a super common complaint from people and it doesn't have a single definitive solution. There are a couple handy tricks:
1. If your classmethod receives any managed objects, you can get a reference to the session from the object itself. For example ``sqlalchemy.orm.object_session(user)``. 2. The easy answer when the above doesn't work is to pass the dbsession into the class method. After this - if still not satisfied - are some hacky things you can do: 1. Stop using classmethod approaches and instead put in a real service layer. This has tons of benefits, see something like pyramid_services for more information about this. This approach will allow you to bind the whole service to a dbsession, and no longer need to pass it around at all. 2. Define a helper to grab the session from the request threadlocal. Something like ``get_current_dbsession = lambda: get_current_request().dbsession``. Then import that and use it via ``dbsession = get_current_dbsession()``. The threadlocal approach above has some downsides but is still better than using a scoped session. Allowing the request to seep into and infect your data model is a little wonky and makes your model code less reusable outside of Pyramid. Even if you are okay with that, something like ``get_current_dbsession().query()`` is going to be better than ``scoped_session.query()`` because it's more explicitly a value that changes over time versus the magic scoped session object proxy. In my own apps I use all the approaches mentioned above except the threadlocal one. - Michael On Mon, Jan 6, 2020 at 2:37 PM Kate Boelhauf <[email protected]> wrote: > A little background - I'm updating my entire site and used a cookiecutter > as referenced in Pyramids docs to do so. I am using sqlalchemy. > > It has a db session as a request method. This works perfectly for me in > all of my views. However, I have class methods in my models that need to > access a session. I can't figure out a way to access the session that the > cookiecutter set up in models.py so I reverted to creating a separate > session using > scoped_session(sessionmaker(extension=ZopeTransactionExtension())) and > importing it into my model and using the request session in my views. > > This just seems wrong - am I approaching this wrong? > > Below is the model.py file that the cookiecutter created: > > from sqlalchemy import engine_from_config > from sqlalchemy.orm import sessionmaker > from sqlalchemy.orm import configure_mappers > 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 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_session_factory(engine): > factory = sessionmaker() > factory.configure(bind=engine) > return factory > > > def get_tm_session(session_factory, 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) > session_factory = get_session_factory(engine) > with transaction.manager: > dbsession = get_tm_session(session_factory, transaction.manager) > > """ > dbsession = session_factory() > 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('tutorial.models')``. > > """ > settings = config.get_settings() > settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager' > > # use pyramid_tm to hook the transaction lifecycle to the request > config.include('pyramid_tm') > > # use pyramid_retry to retry a request when transient exceptions occur > config.include('pyramid_retry') > > session_factory = get_session_factory(get_engine(settings)) > config.registry['dbsession_factory'] = session_factory > > # 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(session_factory, r.tm), > 'dbsession', > reify=True > ) > > > > > > > > > > > -- > You received this message because you are subscribed to the Google Groups > "pylons-discuss" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/pylons-discuss/c60ba3e3-d3ea-4f59-9c94-460c7964c865%40googlegroups.com > <https://groups.google.com/d/msgid/pylons-discuss/c60ba3e3-d3ea-4f59-9c94-460c7964c865%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- Michael -- You received this message because you are subscribed to the Google Groups "pylons-discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/pylons-discuss/CAKdhhwHpJ33fGD3B%3D31YVsjsBAShvWwCk4FQOozR8_tCD1w3Wg%40mail.gmail.com.
