__init__.py 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. # -*- coding: utf-8 -*-
  2. from sqlalchemy import engine_from_config
  3. from sqlalchemy.event import listen
  4. from sqlalchemy.orm import sessionmaker
  5. from sqlalchemy.orm import configure_mappers
  6. import zope.sqlalchemy
  7. from .meta import DeclarativeBase
  8. from .revision_protection import prevent_content_revision_delete
  9. # import or define all models here to ensure they are attached to the
  10. # Base.metadata prior to any initialization routines
  11. from tracim.models.auth import User, Group, Permission
  12. from tracim.models.data import Content, ContentRevisionRO
  13. # run configure_mappers after defining all of the models to ensure
  14. # all relationships can be setup
  15. configure_mappers()
  16. def get_engine(settings, prefix='sqlalchemy.'):
  17. return engine_from_config(settings, prefix)
  18. def get_session_factory(engine):
  19. factory = sessionmaker(expire_on_commit=False)
  20. factory.configure(bind=engine)
  21. return factory
  22. def get_tm_session(session_factory, transaction_manager):
  23. """
  24. Get a ``sqlalchemy.orm.Session`` instance backed by a transaction.
  25. This function will hook the _session to the transaction manager which
  26. will take care of committing any changes.
  27. - When using pyramid_tm it will automatically be committed or aborted
  28. depending on whether an exception is raised.
  29. - When using scripts you should wrap the _session in a manager yourself.
  30. For example::
  31. import transaction
  32. engine = get_engine(settings)
  33. session_factory = get_session_factory(engine)
  34. with transaction.manager:
  35. dbsession = get_tm_session(session_factory, transaction.manager)
  36. """
  37. dbsession = session_factory()
  38. # FIXME - G.M - 02-05-2018 - Check Zope/Sqlalchemy session conf.
  39. # We use both keep_session=True for zope and
  40. # expire_on_commit=False for sessionmaker to keep session alive after
  41. # commit ( in order to not have trouble like
  42. # https://github.com/tracim/tracim_backend/issues/52
  43. # or detached objects problems).
  44. # These problem happened because we use "commit" in our current code.
  45. # Understand what those params really mean and check if it can cause
  46. # troubles somewhere else.
  47. # see https://stackoverflow.com/questions/16152241/how-to-get-a-sqlalchemy-session-managed-by-zope-transaction-that-has-the-same-sc # nopep8
  48. zope.sqlalchemy.register(
  49. dbsession,
  50. transaction_manager=transaction_manager,
  51. keep_session=True,
  52. )
  53. listen(dbsession, 'before_flush', prevent_content_revision_delete)
  54. return dbsession
  55. def includeme(config):
  56. """
  57. Initialize the model for a Pyramid app.
  58. Activate this setup using ``config.include('tracim.models')``.
  59. """
  60. settings = config.get_settings()
  61. settings['tm.manager_hook'] = 'pyramid_tm.explicit_manager'
  62. # use pyramid_tm to hook the transaction lifecycle to the request
  63. config.include('pyramid_tm')
  64. # use pyramid_retry to retry a request when transient exceptions occur
  65. config.include('pyramid_retry')
  66. session_factory = get_session_factory(get_engine(settings))
  67. config.registry['dbsession_factory'] = session_factory
  68. # make request.dbsession available for use in Pyramid
  69. config.add_request_method(
  70. # r.tm is the transaction manager used by pyramid_tm
  71. lambda r: get_tm_session(session_factory, r.tm),
  72. 'dbsession',
  73. reify=True
  74. )