Flask-SQLAlchemy中的相同数据库

mis*_*bin 6 python sqlalchemy flask flask-sqlalchemy

我已经问了一个类似的问题,但我想也许我可以改写它,或者展示我已经做了些什么来进一步阐明这里发生的事情.

目前我有2个相同的数据库,我试图解决这个问题(按照我看到的另一个问题),如下所示:

class BaseTable(db.Model):
    __tablename__ = 'TableName'
    col = db.Column(db.Integer)

class SubTable1(BaseTable):
    __bind_key__ = 'bind1'

class SubTable2(BaseTable):
    __bind_key__ = 'bind2'
Run Code Online (Sandbox Code Playgroud)

这个问题是现在最近的绑定在任何地方使用,所以如果我在其他地方这样做:

SubTable1.query.filter_by(col=12).all()
Run Code Online (Sandbox Code Playgroud)

然后它从第二个数据库获得结果.如果我要切换SubTable类的位置,那么结果是相同的(编辑为了清楚:我的意思是结果来自最后定义的任何绑定,如果它们被切换,它将改为查询来自'bind2'而不是'bind1',就像它目前所做的那样).我真的不知道该怎么做,所以如果你能以任何方式提供帮助,那就太棒了.

谢谢.

编辑:如果这是不可能的(或者你只是知道更好或甚至不同的方式),请告诉我.如果我可以做一些像两个不同的数据库对象那样的东西,那也不错,我只是不知道该怎么做或者会有什么样的含义.

编辑2:经过几个小时的辛苦工作,我终于得出了如何做到这一点的结论.

在__init__.py中:

db1 = SQLAlchemy(app)
db2 = SQLAlchemy(app)
Run Code Online (Sandbox Code Playgroud)

在models.py中:

class Table1(db1.Model):
    __tablename__ = 'TableName'
    __bind_key__ = 'bind1'
    col = db1.Column(db1.Integer)

class Table2(db2.Model):
    __tablename__ = 'TableName'
    __bind_key__ = 'bind2'
    col = db2.Column(db2.Integer)
Run Code Online (Sandbox Code Playgroud)

这种无意义的原因是绑定只能定义一次而不能更改,并且没有两个表名可以相同,即使绑定不同.所以你必须制作2个MetaData实例,否则SQLAlchemy会生气.事实证明,问题是SQLAlchemy的一个限制.

zzz*_*eek 8

我不知道是什么__bind_key__,但是有很多方法可以使用具有多个绑定的单个会话.会话本身可以直接绑定:为此,SubTable1和SubTable2需要单独映射而不是继承层次结构的一部分,因为Session基于最基本映射的类定位绑定.为了共享相同的MetaData,只需将两个类映射到同一个Table对象:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class BaseTable(Base):
    __tablename__ = 'some_table'
    id = Column(Integer, primary_key=True)

class SubTable1(Base):
    __table__ = BaseTable.__table__

class SubTable2(Base):
    __table__ = BaseTable.__table__

db1 = create_engine("sqlite:///db1.db", echo=True, logging_name='db1')
db2 = create_engine("sqlite:///db2.db", echo=True, logging_name='db2')

Base.metadata.create_all(db1)
Base.metadata.create_all(db2)

s = Session(binds={SubTable1: db1, SubTable2: db2})

s.add_all([
    SubTable1(),
    SubTable2(),
    SubTable1(),
    SubTable2(),
    SubTable1(),
])

s.commit()

print s.query(SubTable1).all()
print s.query(SubTable2).all()
Run Code Online (Sandbox Code Playgroud)

这是一种方式.另外,让我们实际上只使用两个不同的MetaData对象,使用mixins很容易:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class BaseTable(object):
    __tablename__ = 'some_table'
    id = Column(Integer, primary_key=True)

class DB1(Base):
    metadata = MetaData()
    __abstract__ = True

class DB2(Base):
    metadata = MetaData()
    __abstract__ = True

class SubTable1(BaseTable, DB1):
    pass

class SubTable2(BaseTable, DB2):
    pass

db1 = create_engine("sqlite:///db1.db", echo=True, logging_name='db1')
db2 = create_engine("sqlite:///db2.db", echo=True, logging_name='db2')

DB1.metadata.create_all(db1)
DB2.metadata.create_all(db2)

s = Session(binds={SubTable1: db1, SubTable2: db2})

s.add_all([
    SubTable1(),
    SubTable2(),
    SubTable1(),
    SubTable2(),
    SubTable1(),
])

s.commit()

print s.query(SubTable1).all()
print s.query(SubTable2).all()
Run Code Online (Sandbox Code Playgroud)

是的,既然我们有两个MetaData对象,我们可以直接"绑定"它们,如果我们想要去那条路线:

# ... mapping as before

DB1.metadata.bind = db1
DB2.metadata.bind = db2
DB1.metadata.create_all()
DB2.metadata.create_all()

s = Session()  # don't need binds in this case

# ... usage as before
s = Session()
Run Code Online (Sandbox Code Playgroud)