【问题标题】:SQLAlchemy ORM: proxy attribute pointing to the first element of a relation?SQLAlchemy ORM:代理属性指向关系的第一个元素?
【发布时间】:2015-04-11 23:11:24
【问题描述】:

从 SQLAlchemy 文档中的many-to-many relationship example 开始,我想添加一个属性first_child,它将返回由关系定义的children 的第一个孩子。 first_child 属性需要在association_proxy 属性定义中可用,例如下面的first_child_id

from sqlalchemy import Table, Column, Integer, ForeignKey
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

association_table = Table('association', Base.metadata,
    Column('left_id', Integer, ForeignKey('left.id')),
    Column('right_id', Integer, ForeignKey('right.id'))
)

class Parent(Base):
    __tablename__ = 'left'
    id = Column(Integer, primary_key=True)
    children = relationship("Child", secondary=association_table)
    first_child = ???
    first_child_id = association_proxy('first_child', 'id')

class Child(Base):
    __tablename__ = 'right'
    id = Column(Integer, primary_key=True)

我想我需要将first_child 声明为hybrid_property or a column_property,但我不知道如何返回第一个元素。

除了first_child,我还需要last_child 和一个关联的last_child_id 属性。

我正在将 SQLAlchemy 与 MySQL 数据库一起使用。

【问题讨论】:

  • 但是使用children.first()有什么问题?
  • @IgorHatarist 你试过吗? 'RelationshipProperty' object has no attribute 'first' 失败
  • 尝试children[0] 获取第一个孩子。但这并不能完全回答你的问题。请问您为什么需要跟踪第一个和最后一个孩子?孩子的排序是如何进行的?
  • @BrechtMachiels 对不起,当然是children[0]
  • @van 是的,children[0] 仅适用于实例。就我而言,孩子是具有开始/结束时间的事件。我想在父级上创建start_timeend_time 属性,分别从第一个和最后一个子级获取值。

标签: python mysql orm sqlalchemy


【解决方案1】:

association_proxy 的问题在于你不能在hybrid_properties 上使用它(或者至少不能直接使用)。

一个简单的解决方案可能是使用 property 装饰器,它将在已加载的实例上进行评估:


class Parent(Base):
    __tablename__ = 'left'
    id = Column(Integer, primary_key=True)
    children = relationship("Child", secondary=association_table)

    @property
    def first_child(self):
        return children[0]

但是,您将无法在查询中使用它,并且它是“只读”属性。更多关于SQLAlchemy plain-descriptor的信息。

【讨论】:

    【解决方案2】:

    如果您需要最小开始时间最大结束时间,那么我会为这些列使用column_property

    association_table = Table(
        'association', Base.metadata,
        Column('left_id', Integer, ForeignKey('left.id')),
        Column('right_id', Integer, ForeignKey('right.id'))
    )
    
    
    class Child(Base):
        __tablename__ = 'right'
        id = Column(Integer, primary_key=True)
        start_time = Column(DateTime)
        end_time = Column(DateTime)
    
    
    class Parent(Base):
        __tablename__ = 'left'
        id = Column(Integer, primary_key=True)
        children = relationship(
            "Child",
            secondary=association_table,
            backref="parents",
        )
    
        min_start_time = column_property(
            select([Child.start_time.label("min_start_time")])
            .where(Child.id == association_table.c.right_id)
            .where(id == association_table.c.left_id)
            .order_by(Child.start_time.asc())
            .limit(1)
        )
    
        max_end_time = column_property(
            select([Child.end_time.label("max_end_time")])
            .where(Child.id == association_table.c.right_id)
            .where(id == association_table.c.left_id)
            .order_by(Child.end_time.desc())
            .limit(1)
            .as_scalar()
        )
    

    但如果您需要从关系中获得多个这样的特殊列,使用hybrid_property 可能会更有效。

    【讨论】:

    • 这会起作用,但我很失望这需要重新定义父子关系。难道不能利用现有的children 属性吗?另外,我需要指向第一个和最后一个孩子的属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 2021-10-27
    • 2021-06-26
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 2013-09-19
    相关资源
    最近更新 更多