版本:1.1.0b2 |发布日期:2016年7月1日

SQLAlchemy 1.1文档

配置关系

与其他类的关系以通常的方式完成,添加的特性是指定给relationship()的类可以是字符串名称。在映射器编译时使用与Base关联的“类注册表”,以将名称解析为实际的类对象,该对象预期在使用映射器配置后定义:

class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    addresses = relationship("Address", backref="user")

class Address(Base):
    __tablename__ = 'addresses'

    id = Column(Integer, primary_key=True)
    email = Column(String(50))
    user_id = Column(Integer, ForeignKey('users.id'))

列结构,因为它们就是这样,可以立即使用,下面我们使用它们定义Address类的主要连接条件:

class Address(Base):
    __tablename__ = 'addresses'

    id = Column(Integer, primary_key=True)
    email = Column(String(50))
    user_id = Column(Integer, ForeignKey('users.id'))
    user = relationship(User, primaryjoin=user_id == User.id)

除了relationship()的主要参数之外,还可以将其他依赖于存在于尚未定义的类中的列的参数指定为字符串。这些字符串被评估为Python表达式。此评估中可用的完整名称空间包括为此声明性基础映射的所有类以及sqlalchemy包的内容,包括desc()func

class User(Base):
    # ....
    addresses = relationship("Address",
                         order_by="desc(Address.email)",
                         primaryjoin="Address.user_id==User.id")

对于多个模块包含同名类的情况,字符串类名称也可以在任何这些字符串表达式中指定为模块限定路径:

class User(Base):
    # ....
    addresses = relationship("myapp.model.address.Address",
                         order_by="desc(myapp.model.address.Address.email)",
                         primaryjoin="myapp.model.address.Address.user_id=="
                                        "myapp.model.user.User.id")

合格的路径可以是删除名称之间的歧义的任何部分路径。例如,为了消除myapp.model.address.Addressmyapp.model.lookup.Address之间的歧义,我们可以指定address.Addresslookup.Address

class User(Base):
    # ....
    addresses = relationship("address.Address",
                         order_by="desc(address.Address.email)",
                         primaryjoin="address.Address.user_id=="
                                        "User.id")

0.8版本中的新功能使用Declarative指定字符串参数时,可以使用模块限定路径,以指定特定模块。

使用基于字符串的属性也有两种选择。也可以使用lambda,这将在所有映射器配置完成后进行评估:

class User(Base):
    # ...
    addresses = relationship(lambda: Address,
                         order_by=lambda: desc(Address.email),
                         primaryjoin=lambda: Address.user_id==User.id)

或者,在类可用之后,可以将关系显式添加到类中:

User.addresses = relationship(Address,
                          primaryjoin=Address.user_id==User.id)

配置多对多关系

多对多关系也可以用声明和传统映射相同的方式声明。relationship()secondary参数像往常一样传递一个Table对象,该对象通常以传统方式声明。Table通常共享声明性基础使用的MetaData对象:

keywords = Table(
    'keywords', Base.metadata,
    Column('author_id', Integer, ForeignKey('authors.id')),
    Column('keyword_id', Integer, ForeignKey('keywords.id'))
    )

class Author(Base):
    __tablename__ = 'authors'
    id = Column(Integer, primary_key=True)
    keywords = relationship("Keyword", secondary=keywords)

像其他relationship()参数一样,也会接受一个字符串,并传递Base.metadata.tables集合中定义的表的字符串名称:

class Author(Base):
    __tablename__ = 'authors'
    id = Column(Integer, primary_key=True)
    keywords = relationship("Keyword", secondary="keywords")

与传统映射一样,除非relationship()被声明,否则使用Table作为也映射到类的“次”参数通常不是一个好主意with viewonly=True否则,工作单元系统可能会尝试对基础表复制INSERT和DELETE语句。