この質問のタイトルに苦労したので、コードをレイアウトしましょう。
ファイル A:
class SomeClass(Base):
__tablename__ = 'some_classes'
id = Column(Integer, primary_key=True)
my_awesome_property = Column(Unicode(255))
other_class = relationship('OtherClass', backref='some_class', uselist=False)
ファイル B:
class OtherClass(Base):
__tablename__ = 'other_classes'
id = Column(Integer, primary_key=True)
my_sweet_property = Column(Unicode(255))
some_class_id = Column(ForeignKey('some_classes.id'))
さて、多くの場合、次のようないくつかの関数を含む「高次」ファイルからこれらのファイルの両方を参照します。
高次ファイル:
from model.alpha import SomeClass
from model.bravo import OtherClass
from sqlalchemy.orm import sessionmaker
session = sessionmaker(bind=some_engine)()
def some_random_query():
return session.query(SomeClass).join(OtherClass).filter(OtherClass.my_sweet_property=='Mike Bayer\'s cat speaks SQL.').first()
それはごく普通のことで、何も問題はありません...まで...ファイルAのような下位レベルのファイルの1つに関数を配置することにしました(そして循環インポートを避けます)
ファイル A に戻る:
# pretend I imported a session here
def frustrating_situation():
session.query(SomeClass).join(SomeClass.other_class).filter(SomeClass.other_class.my_sweet_property=='Get ready for an exception!').first()
これにより、この悪い男の子がここにスローされます。
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with SomeClass.other_class has an attribute 'my_sweet_property'
SQLAlchemy の内部構造について私が知っていることを考えると、これは理にかなっていると思いますが、API の観点からも、ステートメントは実際に機能するはずだと思います。
これが私がそれを回避した方法です:
session.query(SomeClass).join(SomeClass.other_class).filter(SomeClass.other_class.property.mapper.c.my_sweet_property == 'verbose, yet it works as desired').first()
結局のところ、私の質問は非常に単純です。これを行うための、より良い/より慣用的な/適切な/より汚い感じのない方法を知っている人はいますか?
提案を歓迎します。
サイドノート
疑問に思っている人のために:
「結合/フィルター操作のために参照したいクラスをインポートするだけではどうですか?」
クエリを記述しているモジュールにクラスをインポートしたくない/できない理由はいくつかあります。
- クラス定義を多くのファイルに分割し、同じレベルのモジュール間で厳密にインポートしないことで循環インポートを回避することにしました
- 現在定義されていない、または現在のモジュールにインポートされていない 1 つ以上のクラスで動作する関数を配置することを決定しましたが、それらはモジュール内で他の理由で使用されていないため、インポートしたくありません (理由 1 をもう一度参照してください)。