Pylons: совместное использование соединения SQLAlchemy MySQL с внешней библиотекой

Я запускаю Pylons, используя SQLAlchemy для подключения к MySQL, поэтому, когда я хочу использовать подключение к базе данных в контроллере, я могу сделать это:

from myapp.model.meta import Session

class SomeController(BaseController):
    def index(self):
        conn = Session.connection()
        rows = conn.execute('SELECT whatever')
...

Скажем, моему контроллеру нужно вызвать внешнюю библиотеку, для которой также требуется соединение с базой данных, и я хочу предоставить для нее соединение из уже установленного соединения SQLAlchemy MySQL:

from myapp.model.meta import Session

import mymodule

class SomeController(BaseController):
    def index(self):
        conn = Session.connection()
        myobject = mymodule.someobject(DATABASE_OBJECT)
        ...
        conn.close()

Каким должен быть DATABSE_OBJECT? Возможности:

  1. Передайте Session -- а затем откройте и закройте Session.connection() в коде модуля
  2. Передайте conn, а затем вызовите conn.close() в контроллере
  3. Просто передайте параметры соединения, и код модуля настроит собственное соединение.

Есть еще одна проблема: мне нужно создавать экземпляры некоторых объектов в app_globals.py, и этим объектам также требуется подключение к базе данных. Похоже, что app_globals.py еще не может использовать соединение SQLAlchemy Session -- оно еще не привязано.

Является ли моя архитектура принципиально несостоятельной? Не должен ли я таким образом обмениваться соединениями между Pylons и внешними библиотеками? Спасибо!


person mrjf    schedule 28.10.2010    source источник


Ответы (2)


Вы не должны сами управлять соединениями - это все делает SQLAlchemy. Просто используйте объект сеанса с областью действия везде, и все будет в порядке.

def init_model(engine):
    sm = orm.sessionmaker(autoflush=False, autocommit=False, expire_on_commit=False, bind=engine)
    meta.engine = engine
    meta.Session = orm.scoped_session(sm)

def index(self):
    rows = Session.execute('SELECT ...')

Вы можете передать объект сеанса в свою внешнюю библиотеку и выполнять там запросы по своему усмотрению. Нет необходимости вызывать для него .close().

Что касается app_globals, я решил это, добавив другой метод в класс globals, который вызывается после инициализации db из environment.py.

class Globals(...):
    def init_model(self, config):
        self.some_persistent_db_object = Session.execute('...')

def load_environment(...):
    ...
    config['pylons.app_globals'].init_model(config)
    return config
person Daniel Kluev    schedule 29.10.2010
comment
Отличная информация, большое спасибо. Мне нравится подход load_environment, он будет идеальным. Очень признателен! - person mrjf; 30.10.2010

What should DATABSE_OBJECT be? Possibilities:

4. передать «прокси» или «вспомогательный» объект с интерфейсом более высокого уровня абстракции.

Если внешней библиотеке действительно не нужен прямой доступ к сеансу SQLAlchemy, вы можете предоставить ей объект с такими методами, как «get_account(account_no)» вместо «execute(sql)». Это сделало бы код, специфичный для SQLAlchemy, более изолированным, и его также было бы легче тестировать.

Извините, что это не столько ответ на ваш первоначальный вопрос, сколько дизайнерское предложение.

person Pēteris Caune    schedule 29.10.2010
comment
Спасибо Петерис, в целом это хорошая идея. В моем случае внешняя библиотека не связана с моими приложениями Pylons, и предполагается, что она будет работать при обычном подключении к базе данных, поэтому было бы слишком много дублирования, чтобы предоставить ей методы для всего взаимодействия с базой данных. Хотя в некоторых случаях это было бы хорошим архитектурным решением. - person mrjf; 30.10.2010