2013-06-14 35 views
6

Tôi đã hỏi một câu hỏi tương tự, nhưng tôi nghĩ có lẽ tôi có thể nói lại nó, hoặc chỉ ra những gì tôi đã làm thêm để làm sáng tỏ những gì đang xảy ra ở đây.Cơ sở dữ liệu giống hệt trong Flask-SQLAlchemy

Hiện nay tôi có 2 cơ sở dữ liệu giống hệt nhau, và tôi đã cố gắng để giải quyết vấn đề (theo một câu hỏi tôi thấy) như thế này:

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

class SubTable1(BaseTable): 
    __bind_key__ = 'bind1' 

class SubTable2(BaseTable): 
    __bind_key__ = 'bind2' 

Vấn đề ở đây là bây giờ các ràng buộc gần đây nhất là được sử dụng ở mọi nơi, vì vậy nếu tôi làm điều này ở một nơi khác:

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

Sau đó, nó sẽ là kết quả từ cơ sở dữ liệu thứ hai. Nếu tôi chuyển đổi vị trí của lớp SubTable, thì kết quả sẽ giống nhau (Chỉnh sửa để rõ ràng: theo đó tôi có nghĩa là kết quả đến từ bất kỳ liên kết nào được xác định cuối cùng, nếu chúng được chuyển đổi, thay vào đó nó sẽ truy vấn 'bind2' thay vì 'bind1' như hiện tại). Tôi thực sự không biết phải làm gì, vì vậy nếu bạn có thể giúp đỡ bằng bất kỳ cách nào tuyệt vời.

Cảm ơn.

EDIT: Nếu không thể (hoặc bạn chỉ đơn giản là biết một cách tốt hơn hoặc thậm chí khác nhau) để làm điều này, xin vui lòng cho tôi biết. Nếu tôi có thể làm một cái gì đó giống như có hai đối tượng db khác nhau, điều đó cũng sẽ tốt, tôi chỉ không thực sự biết cách thực hiện điều đó hoặc loại tác động nào có thể xảy ra.

EDIT 2: Sau khi làm việc này với giờ và giờ, cuối cùng tôi đã đi đến kết luận về cách thực hiện việc này.

Trong __init__.py:

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

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

Lý do vớ vẩn này là gắn kết chỉ có thể được định nghĩa một lần và không thay đổi, và không có hai tên bảng có thể giống nhau, ngay cả khi các liên kết khác nhau. Vì vậy, bạn phải tạo 2 trường hợp MetaData hoặc SQLAlchemy khác bị điên. Vì vậy, nó chỉ ra vấn đề là một hạn chế trong SQLAlchemy.

Trả lời

8

Tôi không biết __bind_key__ là gì, nhưng có nhiều cách tiếp cận để sử dụng một phiên duy nhất có nhiều liên kết. Phiên bản chính nó có thể bị ràng buộc trực tiếp: để làm điều này, SubTable1 và SubTable2 cần được ánh xạ riêng lẻ và không phải là một phần của một hệ thống phân cấp thừa kế, vì Session xác định ràng buộc dựa trên lớp được ánh xạ cơ bản nhất. Để chia sẻ cùng một MetaData, chỉ cần ánh xạ cả hai lớp vào cùng một đối tượng Bảng:

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

là một cách. Một, chúng ta hãy thực sự chỉ cần sử dụng hai đối tượng MetaData khác nhau, đủ dễ dàng với 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() 

và có, kể từ khi chúng tôi có hai đối tượng MetaData đó, chúng tôi có thể "ràng buộc" chúng trực tiếp, nếu chúng ta muốn đi con đường đó :

# ... 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() 
Các vấn đề liên quan