Le code suivant:
Base = declarative_base()
engine = create_engine(r"sqlite:///" + r"d:\foo.db",
listeners=[ForeignKeysListener()])
Session = sessionmaker(bind = engine)
ses = Session()
class Foo(Base):
__table= "foo"
id = Column(Integer, primary_key=True)
name = Column(String, unique = True)
class Bar(Base):
__table= "bar"
id = Column(Integer, primary_key = True)
foo_id = Column(Integer, ForeignKey("foo.id"))
foo = relationship("Foo")
class FooBar(Base):
__table= "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")
me donne cette erreur:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with FooBar.bar has an attribute 'foo'
Des explications, pourquoi cela se produit-il, et des indications sur la manière dont une telle chose pourrait être réalisée?
En effet, vous essayez d'accéder à bar
à partir de la classe FooBar
plutôt qu'à une instance FooBar
. La classe FooBar
n'est associée à aucun objet bar
--bar
est simplement un sqlalchemy InstrumentedAttribute . C'est pourquoi vous obtenez l'erreur:
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with FooBar.bar has an attribute 'foo'
Vous obtiendrez la même erreur en tapant FooBar.bar.foo.name
en dehors de la requête sqlalchemy.
La solution consiste à appeler directement la classe Foo
:
ses.query(FooBar).join(Bar).join(Foo).filter(Foo.name == "blah")
Je ne peux pas expliquer techniquement ce qui se passe, mais vous pouvez contourner ce problème en utilisant:
ses.query(FooBar).join(Foobar.bar).join(Bar.foo).filter(Foo.name == "blah")
Je recevais la même erreur Neither 'InstrumentedAttribute' object nor 'Comparator' has an attribute
, mais dans mon cas, le problème était que mon modèle contenait une colonne nommée query
, qui remplaçait la propriété interne model.query
.
J'ai décidé de renommer cette colonne en query_text
et cela a supprimé l'erreur. Sinon, passer l'argument name=
à la méthode Column aurait fonctionné: query = db.Column(db.TEXT, name='query_text')
.
Une erreur connexe pouvant être provoquée par une configuration incorrecte de vos relations SQLAlchemy:
AttributeError: Neither 'Column' object nor 'Comparator' object has an attribute 'corresponding_column'
Dans mon cas, j'ai mal défini une relation comme celle-ci:
namespace = relationship(PgNamespace, id_namespace, backref="classes")
L'argument id_namespace
à relationship()
ne devrait tout simplement pas être là. SQLAlchemy tente de l'interpréter comme un argument d'un type différent et échoue avec une erreur impénétrable.