AttributeError при запросе: ни объект InstrumentedAttribute, ни 'Comparator' не имеют атрибута
Следующий код:
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")
дает мне эту ошибку:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with FooBar.bar has an attribute 'foo'
Любые объяснения, почему это происходит, и руководство к тому, как можно достичь такого?
Ответы
Ответ 1
Это происходит потому, что вы пытаетесь получить доступ к bar
из класса FooBar
, а не экземпляра FooBar
. Класс FooBar
не имеет связанных с ним объектов bar
- bar
- это всего лишь sqlalchemy InstrumentedAttribute. Вот почему вы получаете сообщение об ошибке:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with FooBar.bar has an attribute 'foo'
Вы получите ту же ошибку, набрав FooBar.bar.foo.name
вне запроса sqlalchemy.
Решение состоит в том, чтобы вызвать класс Foo
непосредственно:
ses.query(FooBar).filter(Foo.name == "blah")
Ответ 2
Я не могу технически объяснить, что происходит, но вы можете обойти эту проблему, используя:
ses.query(FooBar).join(Foobar.bar).join(Bar.foo).filter(Foo.name == "blah")
Ответ 3
Связанная ошибка, которая может быть вызвана неправильной настройкой отношений SQLAlchemy:
AttributeError: Neither 'Column' object nor 'Comparator' object has an attribute 'corresponding_column'
В моем случае я неправильно определил такое отношение:
namespace = relationship(PgNamespace, id_namespace, backref="classes")
Аргумент id_namespace
для relationship()
должен просто отсутствовать. SQLAlchemy пытается интерпретировать его как аргумент другого типа и не удается с непостижимой ошибкой.