SQLAlchemy - 如何在没有类引用的查询过程中过滤相关类的属性?

时间:2013-05-12 01:49:40

标签: python sqlalchemy

我为这个问题的标题感到挣扎,所以让我只列出代码:

档案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这样的低级文件中(并避免循环导入)

返回文件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 个答案:

答案 0 :(得分:1)

SomeClass.other_class.my_sweet_property

在sqlalchemy中不起作用。遗憾。

您在OtherClass子句中指的是.filter()。你如何得到这个名字是你的事,但从最清楚的方式来看,从每个陈述的含义以及争论的来源仍然只是为了导入东西。

编辑:当您尝试直接从模块中导出名称而不是仅导入模块时,会出现循环导入问题的常见原因。如果您转换代码如下:

from foo import Bar
def baz():
    Bar.quux()
如果foo也试图导入这个模块(例如,因为它想要使用baz),你会遇到导入问题。

通过仅导入模块来修复它:

import foo
def baz()
    foo.Bar.quux()

由于foo.Bar稍后解决,只有在调用baz()时,当此模块导入时您没有遇到任何问题,因为它实际上并没有尝试使用它导入的任何模块的内容。