【问题标题】:SQLAlchemy Join two tables in (1 to 0..1 ) relationshipSQLAlchemy以(1到0..1)关系连接两个表
【发布时间】:2015-07-14 17:45:55
【问题描述】:

我在(1 到 0..1)关系中有这两个表:

models.py

# --------------------------------------------------
class Person(db.Model):
    __tablename__ = 'person'
    id = db.Column(db.Integer, primary_key=True)

    name = db.Column(db.String, nullable=False)
    address = db.Column(db.String, nullable=False)  

# --------------------------------------------------
class Gift(db.Model):
    __tablename__ = 'gift'
    id = db.Column(db.Integer, primary_key=True)

    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
    person = relationship("Person", uselist=False, backref="gift")

    gift_idea = db.Column(db.String, nullable=False)

# --------------------------------------------------

问题:

  1. 我的一对一表的结构是否正确?我知道在 SQLAlchemy 文档中,关系代码行 (person = relationship...) 在父类中,但我需要它在子类中,可以吗?!

  2. 我的目标是显示 (gift_idea from Gift table) 和 (person_name, person_address from Person table),如果该人有 gift_idea。在我的搜索中,我发现人们使用 query.join 来获取它,并且我尝试了很多代码,但是下面的语句至少让我得到了一半的内容 需要:

views.py

    a = session.query(Gift).join(Person)

您能帮我解答我的问题吗?感谢您的努力。

【问题讨论】:

    标签: python-2.7 flask sqlalchemy


    【解决方案1】:

    根据 sqlalchemy 一对一关系模式定义...

    一对一本质上是一个标量的双向关系 两边的属性。为此,uselist 标志指示 标量属性而不是集合的位置 关系的“多”面

    在您的情况下,您通过提供“uselist=False”禁用了礼物的“uselist”(实际上默认情况下它被禁用)。但是您没有为 Persons 禁用“uselist”。因为这个人仍然可以持有礼物清单(一个人 - 许多礼物)。

    您可以在这里通过两种方式获得一对一的映射..

    1:通过使用为反面提供参数的backref 函数。保持原样。

    class Gift(db.Model):
        __tablename__ = 'gift'
        id = db.Column(db.Integer, primary_key=True)
    
        person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
        person = relationship("Person", backref=backref("gift", uselist=False))
    
        gift_idea = db.Column(db.String, nullable=False)
    

    2:在两侧添加标量属性,而不是使用 backref 属性。

    class Gift(db.Model):
        __tablename__ = 'gift'
        id = db.Column(db.Integer, primary_key=True)
    
        person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
        gift_idea = db.Column(db.String, nullable=False)
        person = relationship("Person")
    
    # -----------------------------------------------
    
    class Person(db.Model):
        __tablename__ = 'person'
        id = db.Column(db.Integer, primary_key=True)
    
        name = db.Column(db.String, nullable=False)
        address = db.Column(db.String, nullable=False)
        gift = relationship("Gift", uselist=False)
    

    问题 2 的解决方案:

    @val:为您提供了直接的解决方案。您也可以尝试使用延迟加载,而不是在 orm 查询上清楚地编写所有内容。

    list_of_gift_object = session.query(Gift).join(Person).all()
    

    也许您可以遍历列表并使用 Gift person 属性来获取关联的人员数据。

    for gift in list_of_gift_object:
        print gift.gift_idea, gift.person.name, gift.person.address
    

    【讨论】:

    • 我非常感谢@gsb-eng,您的解释使代码有意义。关于你的 Q2 解决方案,我试过了,但它仍然只打印一个表数据。 “van”代码中的标签显示数据。
    • @Aseel 很有趣,我不知道你是如何尝试的,但如果你仍然想试试看这个(gsb-eng.com/solutions/one_to_one.html
    • @Aseel BTW 关系极大地用于延迟加载,此处结帐提示 (docs.sqlalchemy.org/en/rel_0_9/orm/loading_relationships.html)
    • 再次感谢@gsb-eng 抽出宝贵时间与我联系,从昨天开始我收到了很多有用的信息。现在,在用你的代码检查了我的代码之后,我发现了我的错误。在您的打印声明中:idea.person.name 而我的是 {idea.name} 缺少 .person。!同样在阅读了你给我的关于延迟加载的页面之后,我使用了这个代码而不是a = session.query(Gift).options(joinedload('person')).all(),我更喜欢它,让我的 html 模板看起来更简单。
    【解决方案2】:
    1. 为了从 child 端定义正确的 1 到 [0..1] 关系,您必须确保 backref 设置了 uselist=False,而 @987654323 @从子到父默认为False

      person = db.relationship(
          "Person",
          backref=db.backref("gift", uselist=False),
      )
      
    2. 那么查询就很简单了:

      a = (session
           .query(
               Gift.gift_idea,
               Person.name.label("person_name"),
               Person.address.label("person_address"),
           )
           # .select_from(Gift)  # @note: optional, but will need it if the first column in the `.query(...)` above will be from table `Person`
           .join(Person)
           )
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-12
      相关资源
      最近更新 更多