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

SQLAlchemy 1.1文档

映射表列

mapper()的默认行为是将映射的Table中的所有列组合成映射对象属性,每个属性根据列本身的名称进行命名特别是Columnkey属性)。这种行为可以通过几种方式进行修改。

命名与属性名称不同的列

默认情况下,映射与Column共享与映射属性相同的名称 - 具体而言,它与Column中的Column.key属性匹配。默认情况下它与Column.name相同。

分配给映射到Column的Python属性的名称可以与Column.nameColumn.key不同,只需通过指定,正如我们在一个声明式映射中所说明的那样:

class User(Base):
    __tablename__ = 'user'
    id = Column('user_id', Integer, primary_key=True)
    name = Column('user_name', String(50))

Where above User.id resolves to a column named user_id and User.name resolves to a column named user_name.

映射到现有表格时,可以直接引用Column对象:

class User(Base):
    __table__ = user_table
    id = user_table.c.user_id
    name = user_table.c.user_name

或者在一个经典的映射中,使用所需的键放在properties字典中:

mapper(User, user_table, properties={
   'id': user_table.c.user_id,
   'name': user_table.c.user_name,
})

在下一节中,我们将更仔细地检查.key的用法。

自动化来自反射表的列命名方案

在上一节Naming Columns Distinctly from Attribute Names中,我们展示了显式映射到类的Column如何可以具有与列不同的属性名称。但是如果我们没有明确地列出Column对象,而是使用反射自动生成Table对象(例如Reflecting Database Objects在这种情况下,我们可以使用DDLEvents.column_reflect()事件来拦截Column对象的生成,并为它们提供Column.key

@event.listens_for(Table, "column_reflect")
def column_reflect(inspector, table, column_info):
    # set column.key = "attr_<lower_case_name>"
    column_info['key'] = "attr_%s" % column_info['name'].lower()

在上面的事件中,Column对象的反射将被我们的事件拦截,这个事件添加了一个新的“.key”元素,例如映射如下:

class MyClass(Base):
    __table__ = Table("some_table", Base.metadata,
                autoload=True, autoload_with=some_engine)

如果我们想限定事件只对上面的特定MetaData对象作出反应,我们可以在我们的事件中检查它:

@event.listens_for(Table, "column_reflect")
def column_reflect(inspector, table, column_info):
    if table.metadata is Base.metadata:
        # set column.key = "attr_<lower_case_name>"
        column_info['key'] = "attr_%s" % column_info['name'].lower()

命名带有前缀的所有列¶

对列名进行前缀的快速方法,通常是在映射到现有的Table对象时使用column_prefix

class User(Base):
    __table__ = user_table
    __mapper_args__ = {'column_prefix':'_'}

以上将放置_user_id_user_name_password等属性名称。在映射的User类上。

这种方法在现代用法中是不常见的。为了处理反映的表格,更灵活的方法是使用Automating Column Naming Schemes from Reflected Tables中描述的方法。

使用column_property作为列级选项

使用column_property()函数映射Column时可以指定选项。这个函数明确地创建了mapper()用来跟踪ColumnColumnProperty。通常,mapper()会自动创建。使用column_property(),我们可以传递关于如何映射Column的其他参数。在下面,我们传递一个选项active_history,它指定对这个列值的改变应该导致先前的值被加载:

from sqlalchemy.orm import column_property

class User(Base):
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True)
    name = column_property(Column(String(50)), active_history=True)

column_property() is also used to map a single attribute to multiple columns. 这个用例在映射到具有相等的属性的join()时出现:

class User(Base):
    __table__ = user.join(address)

    # assign "user.id", "address.user_id" to the
    # "id" attribute
    id = column_property(user_table.c.id, address_table.c.user_id)

有关此用法的更多示例,请参阅Mapping a Class against Multiple Tables

Another place where column_property() is needed is to specify SQL expressions as mapped attributes, such as below where we create an attribute fullname that is the string concatenation of the firstname and lastname columns:

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    firstname = Column(String(50))
    lastname = Column(String(50))
    fullname = column_property(firstname + " " + lastname)

SQL Expressions as Mapped Attributes中查看此用法的示例。

sqlalchemy.orm.column_property(*columns, **kwargs)

提供一个用于Mapper的列级属性。

通常可以直接使用Column元素将基于列的属性应用于映射器的properties字典。当给定的列不是直接出现在映射器的可选择范围内时,使用这个函数;示例包括SQL表达式,函数和标量SELECT查询。

不存在于映射器中的列将不会被映射器持久保存,而是有效的“只读”属性。

参数:
  • * cols - 要被映射的列对象列表。
  • active_history = False -

    True时,表示标量属性的“previous”值在替换时应加载,如果尚未加载。通常情况下,简单的非主键标量值的历史跟踪逻辑只需要知道“新”值就可以执行刷新。该标志可用于使用attributes.get_history()Session.is_modified()的应用程序,该应用程序也需要知道属性的“上一个”值。

    New in version 0.6.6.

  • comparator_factory – a class which extends ColumnProperty.Comparator which provides custom SQL clause generation for comparison operations.
  • group – a group name for this property when marked as deferred.
  • deferred – when True, the column property is “deferred”, meaning that it does not load immediately, and is instead loaded when the attribute is first accessed on an instance. 另见deferred()
  • doc – optional string that will be applied as the doc on the class-bound descriptor.
  • expire_on_flush = True -

    禁用刷新过期。引用SQL表达式(而不是单个表绑定列)的column_property()被认为是“只读”属性;填充它对数据状态没有影响,只能返回数据库状态。因为这个原因,一个column_property()的值在父对象被包含在一个flush中,即在flush中有任何种类的“dirty”状态时都会过期。将该参数设置为False将会产生在冲洗过程结束后保留​​现有值的效果。但请注意,具有默认到期设置的Session仍会在Session.commit()调用之后过期。

    New in version 0.7.3.

  • info -

    可选数据字典将被填充到此对象的MapperProperty.info属性中。

    0.8版本中的新功能

  • extension – an AttributeExtension instance, or list of extensions, which will be prepended to the list of attribute listeners for the resulting descriptor placed on the class. 已过时。 T0>请参阅AttributeEvents

映射表列的子集

有时,使用Reflecting Database Objects中描述的反射过程使Table对象可用于从数据库加载表结构。对于有很多不需要在应用程序中引用的列的表,include_propertiesexclude_properties参数可以指定只有一部分列应该是映射。例如:

class User(Base):
    __table__ = user_table
    __mapper_args__ = {
        'include_properties' :['user_id', 'user_name']
    }

...将User类映射到user_table表,仅包括user_iduser_name列 - 其余的都没有引用。同理:

class Address(Base):
    __table__ = address_table
    __mapper_args__ = {
        'exclude_properties' : ['street', 'city', 'state', 'zip']
    }

...将Address类映射到address_table表,包括除streetcity之外的所有列。 statezip

当使用这个映射时,不包含的列在Query发出的任何SELECT语句中不会被引用,也不会在表示列的映射类上有任何映射属性;分配该名称的属性将不会超出正常Python属性分配的作用。

在某些情况下,多个列可能具有相同的名称,例如映射到共享某个列名的两个或多个表的连接时。include_propertiesexclude_properties也可以容纳Column对象来更准确地描述应该包含或排除哪些列:

class UserAddress(Base):
    __table__ = user_table.join(addresses_table)
    __mapper_args__ = {
        'exclude_properties' :[address_table.c.id],
        'primary_key' : [user_table.c.id]
    }

注意

insert and update defaults configured on individual Column objects, i.e. those described at Column Insert/Update Defaults including those configured by the default, update, server_default and server_onupdate arguments, will continue to function normally even if those Column objects are not mapped. 这是因为在defaultupdate的情况下,Column对象仍然存在于Table中,从而允许在ORM发出INSERT或UPDATE时发生缺省函数,而在server_defaultserver_onupdate的情况下,关系数据库本身维护这些函数。