6

私はすでに同様の質問をしましたが、おそらくそれを言い換えるか、ここで何が起こっているのかを明らかにするためにさらに何をしたかを示すことができると思いました.

現在、私は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()

次に、2 番目のデータベースから結果を取得します。SubTable クラスの場所を切り替えた場合、結果は同じです (明確にするために編集: つまり、最後に定義されたバインドから結果が得られることを意味します。現在の「bind1」ではなく「bind2」)。どうすればいいのかわからないので、少しでもお役に立てれば幸いです。

ありがとう。

編集:これを行うことが不可能な場合(または、単により良い方法または別の方法を知っている場合)、私に知らせてください. 2つの異なるdbオブジェクトを持つようなことができれば、それも良いでしょう.それを行う方法や、それがどのような影響を与えるかは本当にわかりません.

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

このナンセンスな理由は、バインドは 1 回しか定義できず、変更できないためです。また、バインドが異なっていても、2 つのテーブル名が同じであってはなりません。したがって、2 つの MetaData インスタンスを作成する必要があります。そうしないと、SQLAlchemy が怒ってしまいます。したがって、問題は SQLAlchemy の制限であることがわかりました。

4

1 に答える 1

8

何が何だかわかりませんが__bind_key__、単一のセッションを複数のバインドで使用する方法はたくさんあります。セッション自体は直接バインドできます。これを行うには、サブテーブル 1 とサブテーブル 2 を個別にマップする必要があり、継承階層の一部ではありません。セッションは、最も基本的にマップされたクラスに基づいてバインドを見つけるためです。同じ 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()

それは一つの方法です。もう 1 つは、実際には 2 つの異なる MetaData オブジェクトを使用してみましょう。mixin を使えば簡単です。

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

はい、そこには 2 つの 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()
于 2013-06-17T05:28:44.763 に答える