简体   繁体   English

Flask-SQLAlchemy中的相同数据库

[英]Identical databases in Flask-SQLAlchemy

I've already asked a similar question, but I thought maybe I could rephrase it, or show what I've done further to shed some light onto what's going on here. 我已经问了一个类似的问题,但我想也许我可以改写它,或者展示我已经做了些什么来进一步阐明这里发生的事情。

Currently I have 2 identical databases, and I've attempted to solve the problem (as per another question I saw) like this: 目前我有2个相同的数据库,我试图解决这个问题(按照我看到的另一个问题),如下所示:

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

class SubTable1(BaseTable):
    __bind_key__ = 'bind1'

class SubTable2(BaseTable):
    __bind_key__ = 'bind2'

The problem with this is that now the most recent bind is used everywhere, so if I do this somewhere else: 这个问题是现在最近的绑定在任何地方使用,所以如果我在其他地方这样做:

SubTable1.query.filter_by(col=12).all()

Then it gets results from the second database. 然后它从第二个数据库获得结果。 If I were to switch the locations of the SubTable classes, then the results are the same (Edit for clarity: by which I mean that the results come from whatever bind is defined last, if they were to be switched, it would instead query from 'bind2' instead of 'bind1' as it currently does). 如果我要切换SubTable类的位置,那么结果是相同的(编辑为了清楚:我的意思是结果来自最后定义的任何绑定,如果它们被切换,它将改为查询来自'bind2'而不是'bind1',就像它目前所做的那样)。 I don't really know what to do, so if you can help in any way that would be awesome. 我真的不知道该怎么做,所以如果你能以任何方式提供帮助,那将是非常棒的。

Thanks. 谢谢。

EDIT: If it's impossible (or you simply know a better or even different way) to do this, please let me know. 编辑:如果这是不可能的(或者你只是知道更好或甚至不同的方式),请告诉我。 If I could do something like having two different db objects, that would be good as well, I just don't really know how to do that or what kind of implications that would have. 如果我可以做两个不同的数据库对象之类的事情,那也就是好事,我真的不知道该怎么做或者会有什么样的含义。

EDIT 2: After toiling with this for hours and hours, I've finally come to a conclusion on how to do this. 编辑2:经过几个小时的辛苦工作,我终于得出了如何做到这一点的结论。

In __init__.py: 在__init__.py中:

db1 = SQLAlchemy(app)
db2 = SQLAlchemy(app)

In models.py: 在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)

The reason for this nonsense is that binds can only be defined once and not changed, and no two table names can be the same, even if the binds are different. 这种无意义的原因是绑定只能定义一次而不能更改,并且没有两个表名可以相同,即使绑定不同。 So you have to make 2 MetaData instances or else SQLAlchemy gets mad. 所以你必须制作2个MetaData实例,否则SQLAlchemy会生气。 So it turns out the problem is a limitation in SQLAlchemy. 事实证明,问题是SQLAlchemy的一个限制。

I don't know what __bind_key__ is, but there are many approaches to using a single Session with multiple binds. 我不知道__bind_key__是什么,但是有很多方法可以使用具有多个绑定的单个Session。 Session itself can be bound directly: to do this, SubTable1 and SubTable2 need to be mapped individually and not part of an inheritance hierarchy, as the Session locates the bind based on the base-most mapped class. 会话本身可以直接绑定:为此,SubTable1和SubTable2需要单独映射而不是继承层次结构的一部分,因为Session基于最基本映射的类定位绑定。 In order to share the same MetaData, just map both classes to the same Table object: 为了共享相同的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()

that's one way. 这是一种方式。 Another, let's actually just use two different MetaData objects, easy enough with mixins: 另外,让我们实际上只使用两个不同的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()

and yes, since we have the two MetaData objects there, we can "bind" them directly, if we want to go that route: 是的,既然我们有两个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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM