长链存在查询,链中有多个一对多映射

时间:2014-01-20 09:14:53

标签: python postgresql sqlalchemy

编辑:以下内容似乎是正确的方式: session.query(User).join("userGadgets", "gadget", "components","gadgetComponentMetals")

原始: 我配置了以下表格:

class User(Base):
    __tablename__ = "user"

    id = Column(Integer, primary_key=True)
    name = Column(String)


class Gadget(Base):
    __tablename__ = "gadget"

    id = Column(Integer, primary_key=True)
    brand = Column(String)


class UserGadget(Base):
    __tablename__ = "user_gadget"

    user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
    gadget_id = Column(Integer, ForeignKey('gadget.id'), primary_key=True)

    user = relationship("User", backref=backref('userGadgets', order_by=user_id))
    gadget = relationship("Gadget", backref=backref('userGadgets', order_by=gadget_id))


class GadgetComponent(Base):
    __tablename__ = "gadget_component"

    id = Column(String, primary_key=True)
    gadget_id = Column(Integer,ForeignKey('gadget.id'))
    component_maker = Column(String)

    host = relationship("Gadget", backref=backref('components', order_by=id))


class ComponentUsingMetal(Base):
    __tablename__ = "component_metal"

    id = Column(Integer, primary_key=True)    
    component_id = Column(Integer, ForeignKey('GadgetComponent.id'))  
    metal = Column(String)

    component = relationship("GadgetComponent", backref=backref('gadgetComponentMetals', order_by=id))

我想找到拥有至少一个包含某种金属的组件的小工具的用户的所有用户名。对此的SQL查询将是:

SELECT distinct u.name FROM user u join user_gadget ug on (u.id = ug.user_id) join gadget_component gc on (ug.gadget_id = gc.id) join component_metal cm on (gc.id = cm.component_id) order by u.name

我尝试过各种版本:session.query(User).filter(User.userGadgets.any(UserGadget.gadget.components.any(GadgetComponent.gadgetComponentMetals.exists())))

我收到以下错误: AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with UserGadget.gadget has an attribute 'gadgetComponents'

关于我做错了什么的想法,还是有更好的方法在SQLAlchemy中进行这种查询?

1 个答案:

答案 0 :(得分:2)

join()是更好的方法,因为any()将产生大量昂贵的嵌套子查询。但是您使用“any”所犯的错误是使用如下语法:UserGadget.gadget.components。 SQLAlchemy不会像这样继承系列中的属性命名空间,例如没有UserGadget.gadget.components;分别只有UserGadget.gadgetGadget.components。就像SQL不会让你说“SELECT * from user_gadget.gadget_id.gadget.component_id”之类的东西,SQLAlchemy需要你告诉它你想如何将你要查询的多个表连接在一起。这里的any()类似于any(and_(UserGadget.gadget_id == GadgetComponent.gadget_id)),但无论如何使用JOIN会更好。