版本: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语句。