2013-06-14 2 views
6

Я уже задал аналогичный вопрос, но я подумал, может быть, я мог бы перефразировать его или показать, что я сделал дальше, чтобы пролить свет на то, что здесь происходит.Идентичные базы данных в 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' 

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

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

Затем он получает результаты из второй базы данных. Если бы я должен был переключать местоположения классов SubTable, то результаты были одинаковыми (Edit for clearity: под которым я подразумеваю, что результаты исходят из того, что было определено последним, если они должны были переключаться, вместо этого запрос 'bind2' вместо 'bind1', как это сейчас делает). Я действительно не знаю, что делать, поэтому, если вы можете каким-то образом помочь, это будет потрясающе.

Спасибо.

EDIT: Если это невозможно (или вы просто знаете лучше или даже по-другому), сделайте это, пожалуйста, дайте мне знать. Если бы я мог делать что-то вроде двух разных объектов db, это было бы хорошо, я просто не знаю, как это сделать или какие последствия могут иметь последствия.

РЕДАКТИРОВАТЬ 2: После этого с часами и часами я наконец пришел к выводу о том, как это сделать.

В __init__.py:

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

В 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) 

Причиной этого бреда является то, что связывает не может быть определен только один раз и не изменилось, и нет двух имен таблиц могут быть одинаковыми, даже если привязки разные. Поэтому вам нужно сделать 2 экземпляра MetaData, иначе SQLAlchemy разозлится. Таким образом, проблема заключается в ограничении в SQLAlchemy.

ответ

8

Я не знаю, что такое __bind_key__, но существует множество подходов к использованию одного сеанса с несколькими связями. Сам сеанс может быть связан напрямую: для этого SubTable1 и SubTable2 должны отображаться индивидуально, а не часть иерархии наследования, поскольку Session находит привязку на основе базового класса. Для того, чтобы одну и ту же MetaData, просто карта обоих классов к одному объекту таблице:

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() 

, что один из способов. Другой, давайте на самом деле просто использовать два различные объект метаданных, достаточно легко с Примесью:

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() 

и да, так как у нас есть два объекта МЕТАДАННЫХ там, мы можем «связать» их непосредственно, если мы хотим идти по этому пути :

# ... 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() 
Смежные вопросы