Sqlalchemy能否与多个附加的SQLite数据库文件良好配合?

11 投票
1 回答
4713 浏览
提问于 2025-04-18 02:31

你可以通过使用“ATTACH”语句把多个SQLite数据库连接在一起,并且可以一起操作它们。每个SQLite文件中的表可以通过特定的关键词来引用。这样,你就可以同时处理多个同名的表,只需要通过文件来区分。这里有一个很好的教程,教你如何做到这一点:

http://longweekendmobile.com/2010/05/29/how-to-attach-multiple-sqlite-databases-together/

我觉得可以用SQLAlchemy的表“schema”关键词来区分连接到多个文件的情况。当我寻找如何用SQLAlchemy处理通过ATTACH连接的SQLite数据库时,只找到了这个例子。可惜的是,这个例子有点过时,似乎在当前版本中不太适用。

https://groups.google.com/forum/#!topic/sqlalchemy/QXqs4M2MjbY

我尝试用声明类等来更新那个例子。这是我的尝试:

from sqlalchemy import *
from sqlalchemy.orm import * 
from sqlalchemy.ext.declarative import *
#from sqlalchemy.pool import SingletonThreadPool

metadata = MetaData(object)
DeclarativeBase = declarative_base(metadata=metadata)

##########################################################################
# Classes
##########################################################################

class A(DeclarativeBase):
    __table__              = Table('A', DeclarativeBase.metadata,
                                   Column('id', Integer, primary_key=True, index=True, autoincrement=True),
                                   Column('col_a', Integer, index=True))

class B(DeclarativeBase):
    __table__              = Table('B', DeclarativeBase.metadata,
                                   Column('id', Integer, primary_key=True, index=True, autoincrement=True),
                                   Column('col_b', Integer, index=True),
                                   schema='database_b')

#engine = create_engine('sqlite:////tmp/database_a.sqlite',echo=True, poolclass=SingletonThreadPool)
engine = create_engine('sqlite:////tmp/database_a.sqlite',echo=True)
db     = engine.connect()
db.execute("ATTACH DATABASE '/tmp/database_b.sqlite' AS database_b")

DeclarativeBase.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
session.commit()

可惜,我得到了以下输出:

monster:tmp ladmin$ python sqliteattachtest2.py 
2014-04-12 18:04:58,845 INFO sqlalchemy.engine.base.Engine ATTACH DATABASE '/tmp/database_b.sqlite' AS database_b
2014-04-12 18:04:58,845 INFO sqlalchemy.engine.base.Engine ()
2014-04-12 18:04:58,846 INFO sqlalchemy.engine.base.Engine PRAGMA "database_b".table_info("B")
2014-04-12 18:04:58,846 INFO sqlalchemy.engine.base.Engine ()
2014-04-12 18:04:58,846 INFO sqlalchemy.engine.base.Engine ROLLBACK
Traceback (most recent call last):
  File "sqliteattachtest2.py", line 29, in <module>
    DeclarativeBase.metadata.create_all(engine)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/schema.py", line 2793, in create_all
    tables=tables)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1479, in _run_visitor
    conn._run_visitor(visitorcallable, element, **kwargs)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1122, in _run_visitor
    **kwargs).traverse_single(element)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/sql/visitors.py", line 111, in traverse_single
    return meth(obj, **kw)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/ddl.py", line 57, in visit_metadata
    if self._can_create_table(t)]
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/ddl.py", line 35, in _can_create_table
    table.name, schema=table.schema)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/dialects/sqlite/base.py", line 716, in has_table
    cursor = _pragma_cursor(connection.execute(statement))
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 662, in execute
    params)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 805, in _execute_text
    statement, parameters
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 874, in _execute_context
    context)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1024, in _handle_dbapi_exception
    exc_info
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 195, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 867, in _execute_context
    context)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 324, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (OperationalError) unknown database "database_b" 'PRAGMA "database_b".table_info("B")' ()

我听说这种事情可以通过Postgres的schema来实现。多个附加的SQLite数据库似乎是一个自然的对应关系。我怀疑我可能做错了什么,或者漏掉了什么重要的点。是否可以用SQLAlchemy同时处理多个SQLite文件?如果可以,最好的方法是什么?有没有其他的ORM比SQLAlchemy更容易做到这一点?

谢谢!

1 个回答

11

创建一个内存中的SQLite引擎,然后连接不同的数据库文件。

from sqlalchemy import create_engine, MetaData, Table,Column,Integer,select
from sqlalchemy.orm import mapper, sessionmaker
from sqlite3 import dbapi2 as sqlite
from sqlalchemy.engine.reflection import Inspector

class Bookmarks(object):
    pass

class BookmarksB(object):
    pass



def loadSession():
    engine = create_engine('sqlite://', echo=True)
    engine.execute("attach database 'database_b' as BB;")
    engine.execute("attach database 'database_a' as AA;")
    metadata = MetaData(engine)


    inspector = Inspector.from_engine(engine)
    print inspector.get_table_names()

    moz_bookmarks = Table('table_a', metadata,Column("id", Integer, primary_key=True),schema='AA', autoload=True)
    mapper(Bookmarks, moz_bookmarks)
    moz_bookmarksB = Table('table_b', metadata,Column("id", Integer, primary_key=True),schema='BB', autoload=True)
    mapper(BookmarksB, moz_bookmarksB)

    Session = sessionmaker(bind=engine)
    session = Session()
    return session

if __name__ == "__main__":
    session = loadSession()
    res = session.query(Bookmarks).all()
    for m in res:
        print m.msisdn,m.id

    #print list(select([moz_bookmarks, moz_bookmarksB], moz_bookmarks.c.b_id == moz_bookmarksB.c.id).execute())

撰写回答