2012-08-18 2 views
2

В моем приложении WSGI используется SQLAlchemy. Я хочу начать сеанс при запуске запроса, зафиксировать его, если он грязный, и обработка запроса завершена успешно, в противном случае выполните откат. Итак, мне нужно реализовать поведение Django's TransactionMiddleware.Связующее приложение WSGI для обработки SQLAlchemy session

Итак, я полагаю, что я должен создать WSGI промежуточное программное обеспечение и сделать следующие вещи:

  1. Создать и добавить DB сессию environ на предварительной обработки.
  2. Получите сеанс БД от environ и вызовите commit() на пост-обработку, если ошибок не было.
  3. Получите сеанс БД от environ и вызовите rollback() при последующей обработке, если произошли некоторые ошибки.

Шаг 1 Для меня очевидно:

class DbSessionMiddleware: 
def __init__(self, app): 
    self.app = app 

def __call__(self, environ, start_response): 
    environ['db_session'] = create_session() 
    return self.app(environ, start_response) 

Шаг 2 и 3 - нет. Я нашел example пост-обработки задачи:

class Caseless: 
def __init__(self, app): 
    self.app = app 

def __call__(self, environ, start_response): 
    for chunk in self.app(environ, start_response): 
     yield chunk.lower() 

Он содержит комментарий:

Обратите внимание, что функция __call__ является генератор Python, который является типичным для такого рода «пост-обработки» задачи ,

Не могли бы вы прояснить, как это работает и как я могу решить свою проблему аналогичным образом.

Спасибо, Борис.

ответ

2

На шаге 1 я использую SQLAlchemy scoped sessions:

engine = create_engine(settings.DB_URL, echo=settings.DEBUG, client_encoding='utf8') 
Base = declarative_base() 

sm = sessionmaker(bind=engine) 
get_session = scoped_session(sm) 

Они возвращают один и тот же внутрипотоковой сеанс для каждого get_session() вызова.

Шаг 2 и 3 на данный момент заключается в следующем:

class DbSessionMiddleware: 
def __init__(self, app): 
    self.app = app 

def __call__(self, environ, start_response): 
    try: 
     db.get_session().begin_nested() 
     return self.app(environ, start_response) 
    except BaseException: 
     db.get_session().rollback() 
     raise 
    finally: 
     db.get_session().commit() 

Как вы можете видеть, я начинаю вложенную транзакцию на сессии, чтобы иметь возможность откатить даже запросы, которые уже были совершены в представлениях.

+0

Могу ли я безопасно использовать 'db.get_session()' inside' self.app'? Например, вот так: 'db.get_session(). Query (...)'? Или возникают проблемы с локальным хранилищем потоков? –