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'

Любые объяснения, почему это происходит, и рекомендации о том, как это может быть достигнуто?


person Bleeding Fingers    schedule 16.05.2013    source источник


Ответы (4)


Это связано с тем, что вы пытаетесь получить доступ к bar из класса FooBar, а не из экземпляра FooBar. Класс FooBar не имеет связанных с ним объектов bar --bar является просто InstrumentedAttribute sqlalchemy. Вот почему вы получаете ошибку:

AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with FooBar.bar has an attribute 'foo'

Вы получите ту же ошибку, набрав FooBar.bar.foo.name вне запроса sqlalchemy.

Решение состоит в том, чтобы вызвать класс Foo напрямую:

ses.query(FooBar).join(Bar).join(Foo).filter(Foo.name == "blah")
person ostrokach    schedule 15.07.2014
comment
Что делать, если таблица имеет несколько связей с Foo? - person rr-; 07.05.2016
comment
Я думаю, что этот ответ неверен! Он выдает это: SELECT foobar.id AS foobar_id, foobar.bar_id AS foobar_bar_id FROM foobar, foo WHERE foo.name = ?, который НЕ объединяет таблицы перед выполнением фильтра. - person Jim Hunziker; 06.11.2018
comment
@anvd Я исправил свой ответ. Извините за путаницу. - person ostrokach; 20.11.2018

Я не могу технически объяснить, что происходит, но вы можете обойти эту проблему, используя:

ses.query(FooBar).join(Foobar.bar).join(Bar.foo).filter(Foo.name == "blah")
person Bleeding Fingers    schedule 17.05.2013
comment
Вы можете понять, почему это работает, из документации: docs. sqlalchemy.org/en/rel_0_9/orm/ - person Flamínio Maranhão; 28.11.2014
comment
Это правильно, а принятый ответ неверен, потому что он не объединяет таблицы по их внешним ключам. На самом деле вы можете удалить .bar и .foo из этого ответа, и он все еще работает. - person Jim Hunziker; 06.11.2018

Я получал ту же ошибку Neither 'InstrumentedAttribute' object nor 'Comparator' has an attribute, но в моем случае проблема заключалась в том, что моя модель содержала столбец с именем query, который перезаписывал внутреннее свойство model.query.

Я решил переименовать этот столбец в query_text, и это устранило ошибку. В качестве альтернативы сработала бы передача аргумента name= методу Column: query = db.Column(db.TEXT, name='query_text').

person tokenizer_fsj    schedule 23.07.2018

Связанная ошибка, которая может быть вызвана неправильной настройкой отношений SQLAlchemy:

AttributeError: Neither 'Column' object nor 'Comparator' object has an attribute 'corresponding_column'

В моем случае я неправильно определил такое отношение:

namespace   = relationship(PgNamespace, id_namespace, backref="classes")

Аргумента id_namespace для relationship() вообще не должно быть. SQLAlchemy пытается интерпретировать его как аргумент другого типа и терпит неудачу с непостижимой ошибкой.

person qris    schedule 04.02.2016
comment
Благодарю вас! Столбец и отношение с одинаковым именем вызывали эту ошибку, и я не заметил ее, пока не прочитал этот ответ. - person gatherer; 23.09.2019