我为这个问题的标题而苦苦挣扎,所以让我列出代码:
档案一:
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(并避免循环导入)
返回文件 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)。