【问题标题】:Flask/SQLAlchemy - query relationship AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with has an attributeFlask/SQLAlchemy - 查询关系AttributeError:关联的'InstrumentedAttribute'对象和'Comparator'对象都没有属性
【发布时间】:2021-08-31 23:11:09
【问题描述】:

这很好用

protocols = db.session.query(Protocol.id, Protocol.customer_id).all()

结果

[(1, 1), (2, 1)]

如果我尝试在查询中包含关系列 (Protokol.zakaznik.objednatel) 而不是 Protocol.customer_id,它将返回:AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object associated with Protocol.zakaznik has an attribute 'objednatel'

protocols = db.session.query(Protocol.id, Protocol.zakaznik.objednatel).all()

如果我遍历协议,则关系会很好

protocols = db.session.query(Protocol).all()
for protocol in protocols:
    print(protocol.zakaznik.objednatel)
    print(protocol.zakaznik.id)

那么在查询中使用关系有什么问题呢?是否可以返回[(1, CustomerObjednatel1), (2, CustomerObjednatel1)]?我当然可以做连接查询,效果很好。我认为使用关系会更短。

models.py

class Customer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    objednatel = db.Column(db.String(120), unique=True, nullable=False)
    protocols = db.relationship('Protocol', back_populates='zakaznik')
    

class Protocol(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    customer_id = db.Column(db.Integer, db.ForeignKey('customer.id'), nullable=False)
    zakaznik =  db.relationship('Customer', back_populates='protocols')

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    所以我终于在 SO 上找到了几乎相同的问题 here

    从那里的答案看来,session.query 不能将关系作为参数。他们链接docs reference,其中写着实体将作为参数出现。所以我猜这个关系不是实体(实体的属性)并且 session.query 不能消费它。如果有人可以确认,那就太好了,但我想就是这样。

    【讨论】:

      【解决方案2】:

      不要定义可以在Protocol模型中设置backref的模型,参考docs

      class Customer(db.Model):
      id = db.Column(db.Integer, primary_key=True)
      objednatel = db.Column(db.String(120), unique=True, nullable=False)
      protocols = db.relationship('Protocol',backref="cus")
      
      
      class Protocol(db.Model):
          id = db.Column(db.Integer, primary_key=True)
          customer_id = db.Column(db.Integer, db.ForeignKey('customer.id'), nullable=False)
          
      

      你可以这样查询

      customer1 = Customer.query.filter_by(id=1).first()
      customer1.protocols[0].id // gives the id of the first protocol of customer1
      

      查询协议,您可以使用带有cus 的backref 来访问整个对象Customer

      protocol2 = Protocol.query.filter_by(id=2).first()
      protocol2.cus // gives the full information of object something like - <Customer 2>
      protocol2.cus.objednatel  // gives the objednatel of protocol2's customer 
      

      大家可以关注video了解更多

      【讨论】:

      • 根据我的阅读,我认为 back_populates 和 backref 是等价的(参见here)。但是,是的,您编写查询的方式 - 这是有效的。很抱歉理解缓慢,但您能解释一下为什么我总是需要按特定客户过滤才能访问 cus 关系吗?为什么我不能查询所有具有 cus 关系的协议?这是因为关系“列”的工作方式?
      • 你可以像 p = Protocol.query.filter_by().all() 这样查询所有协议,这给出了一个对象列表,像 for i in p: print(p.cus , p.objednatel) 一样遍历它们。跨度>
      • 好的,它也可以在没有 filter_by() 的情况下工作,只是 Protocol.query.all(),但是当我写 db.session.query(Protocol.id, Protocol.customer_id).all() 时这将返回 [&lt;Protocol 1&gt;, &lt;Protocol 2&gt;] 然后这将返回 [(1, 1), (2, 1)] 但回到原来的问题为什么这不起作用db.session.query(Protocol.id, Protocol.cus.objednatel).all()
      • 我从来没有这样询问过,也许这个 SO questionthis 可以提供帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-01-04
      • 2021-02-12
      • 2016-02-22
      • 2020-07-08
      • 1970-01-01
      • 1970-01-01
      • 2019-03-29
      相关资源
      最近更新 更多