0

SQLAlchemy / Tastypie RESTインターフェイスを使用してデータベース アイテムを挿入するという問題がありますが、後でアイテムのリストを取得するとアイテムが見つかりません。アイテムのリストをもう一度取得した後にのみ表示されます

mod_wsgi を介して Apache で実行されている Tastypie/Django で SQLAlchemy を使用しています。シングルトン データベース マネージャー クラスを使用してエンジンと declarative_base を保持し、Tastypie を使用して別のクラスを使用してセッションを取得し、コミットに問題がある場合は確実にロールバックします。以下の更新のように、挿入後にセッションを閉じないと問題が発生します。 なぜこれが必要なのですか?

私の元のコードは次のようなものでした:

Session = scoped_session(sessionmaker(autoflush=True))

# Singleton Database Manager class for managing session
class DatabaseManager():
    engine = None
    base = None

    def ready(self):
       host='mysql+mysqldb://etc...'
       if self.engine and self.base:
            return True
        else:
            try:
                self.engine = create_engine(host, pool_recycle=3600)
                self.base = declarative_base(bind=self.engine)
                return True
            except:
                return False

    def getSession(self):
        if self.ready():
            session = Session()
            session.configure(bind=self.engine)
            return session
        else:
            return None

DM = DatabaseManager()

# A session class I use with Tastypie to ensure the session is destroyed at the
# end of the transaction, because Tastypie creates singleton Resources used for
# all threads
class MySession:
    def __init__(self):
        self.s = DM.getSession()

    def safeCommit(self):
        try:
            self.s.commit()
        except:
            self.s.rollback()
            raise

    def __del__(self):
        try:
            self.s.commit()
        except:
            self.s.rollback()
            raise


# ... Then ... when I get requests through Apache/mod_wsgi/Django/Tastypie
# First Request
obj_create():
    db = MySession()
    print db.s.query(DBClass).count() # returns 4
    newItem = DBClass()
    db.s.add(newItem)
    db.s.safeCommit()
    print db.s.query(DBClass).count() # returns 5


# Second Request after First Request returns
obj_get_list():
    db = MySession()
    print db.s.query(DBClass).count() # returns 4 ... should be 5


# Third Request is okay
obj_get_list():
    db = MySession()
    print db.s.query(DBClass).count() # returns 5

アップデート

さらに掘り下げた後、作成後にセッションを閉じる必要があることが問題のようです。おそらく、Tastypie の object_create() が SQLAlchemy オブジェクトをそのバンドルに追加し、関数のスコープを離れた後に何が起こるかわかりません。

obj_create():
    db = MySession()
    newItem = DBClass()
    db.s.add(newItem)
    db.s.safeCommit()
    copiedObj = copyObj(newItem) # copy SQLAlchemy record into non-sa object (see below)
    db.s.close()
    return copiedObj

誰かが答えでこれを説明したい場合は、質問を閉じることができます。また、興味のある方のために、次のように SQLAlchemy からオブジェクトをコピーします。

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

class MyTastypieResource(Resource):
    ...
    def copyObject(self, object):
        base = {}
        # self._meta is part of my tastypie resource
        for p in class_mapper(self._meta.object_class).iterate_properties:
            if p.key not in base and p.key not in self._meta.excludes:
                base[p.key] = getattr(object,p.key)
        return Struct(**base)
4

1 に答える 1

0

セッションを閉じることで問題は解決しました。回答の更新は問題を完全には解決しませんでした-トランザクションの最後にセッションを閉じるミドルウェアクラスを追加することになりました。これにより、すべてがデータベースに書き込まれました。ミドルウェアは次のようになります。

class SQLAlchemySessionMiddleWare(object):
    def process_response(self, request, response):
        try:
            session = MyDatabaseManger.getSession()
            session.commit()
            session.close()
        except Exception, err:
            pass
        return response

    def process_exception(self, request, exception):
        try:
            session = MyDatabaseManger.getSession()
            session.rollback()
            session.close()
        except Exception, err:
            pass
于 2012-09-24T19:27:30.617 に答える