Reputation: 7129
The following code:
Base = declarative_base()
engine = create_engine(r"sqlite:///" + r"d:\foo.db",
listeners=[ForeignKeysListener()])
Session = sessionmaker(bind = engine)
ses = Session()
class Foo(Base):
__tablename__ = "foo"
id = Column(Integer, primary_key=True)
name = Column(String, unique = True)
class Bar(Base):
__tablename__ = "bar"
id = Column(Integer, primary_key = True)
foo_id = Column(Integer, ForeignKey("foo.id"))
foo = relationship("Foo")
class FooBar(Base):
__tablename__ = "foobar"
id = Column(Integer, primary_key = True)
bar_id = Column(Integer, ForeignKey("bar.id"))
bar = relationship("Bar")
Base.metadata.create_all(engine)
ses.query(FooBar).filter(FooBar.bar.foo.name == "blah")
is giving me this error:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with FooBar.bar has an attribute 'foo'
Any explanations, as to why this is happening, and guidance to how such a thing could be achieved?
Upvotes: 91
Views: 86952
Reputation: 1702
This is a simple working example with multiple relations to the same table. This generally avoid having the error AttributeError while querying: Neither 'InstrumentedAttribute' object nor 'Comparator' has an attribute
def get_company(db: Session, company_id: int):
best_contact = aliased(User, name="best_contact ")
other_contact = aliased(User, name="other_contact")
row = (
db.query(Company, best_contact, other_contact)
.join(best_contact, Company.best_contact_id == best_contact.id)
.join(other_contact, Company.other_contact_id == other_contact.id)
.filter(Company.id == company_id)
.first()
)
return row
Upvotes: 2
Reputation: 3420
stmt = (
select(Bar.id).
where(Bar.foo.has(Foo.name=="test"))
)
Maybe it will be useful... I found it here: https://docs.sqlalchemy.org/en/14/tutorial/orm_related_objects.html#exists-forms-has-any
Upvotes: 2
Reputation: 19932
This is because you are trying to access bar
from the FooBar
class rather than a FooBar
instance. The FooBar
class does not have any bar
objects associated with it--bar
is just an sqlalchemy InstrumentedAttribute. This is why you get the error:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with FooBar.bar has an attribute 'foo'
You will get the same error by typing FooBar.bar.foo.name
outside the sqlalchemy query.
The solution is to call the Foo
class directly:
ses.query(FooBar).join(Bar).join(Foo).filter(Foo.name == "blah")
Upvotes: 116
Reputation: 1240
I was getting the same error Neither 'InstrumentedAttribute' object nor 'Comparator' has an attribute
, but in my case, the problem was my model contained a Column named query
, which was overwriting the internal property model.query
.
I decided to rename that Column to query_text
and that removed the error. Alternatively, passing the name=
argument to the Column method would have worked: query = db.Column(db.TEXT, name='query_text')
.
Upvotes: 12
Reputation: 7129
I cannot explain technically what happens but you can work around this problem by using:
ses.query(FooBar).join(Foobar.bar).join(Bar.foo).filter(Foo.name == "blah")
Upvotes: 40
Reputation: 8162
A related error that can be caused by configuring your SQLAlchemy relationships incorrectly:
AttributeError: Neither 'Column' object nor 'Comparator' object has an attribute 'corresponding_column'
In my case, I incorrectly defined a relationship like this:
namespace = relationship(PgNamespace, id_namespace, backref="classes")
The id_namespace
argument to relationship()
should just not be there at all. SQLAlchemy is trying to interpret it as an argument of a different type, and failing with an inscrutable error.
Upvotes: 2