Mapping Table Columns — SQLAlchemy 1.2 Documentation

Release: 1.2.5 | Release Date: March 6, 2018

# SQLAlchemy 1.2 Documentation

# Mapping Table Columns

The default behavior of `mapper()` is to assemble all the columns in the mapped `Table` into mapped object attributes, each of which are named according to the name of the column itself (specifically, the `key` attribute of `Column`). This behavior can be modified in several ways.

## Naming Columns Distinctly from Attribute Names

A mapping by default shares the same name for a `Column` as that of the mapped attribute - specifically it matches the `Column.key` attribute on `Column`, which by default is the same as the `Column.name`.

The name assigned to the Python attribute which maps to `Column` can be different from either `Column.name` or `Column.key` just by assigning it that way, as we illustrate here in a Declarative mapping:

    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`.

When mapping to an existing table, the `Column` object can be referenced directly:

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

Or in a classical mapping, placed in the `properties` dictionary with the desired key:

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

In the next section we’ll examine the usage of `.key` more closely.

## Automating Column Naming Schemes from Reflected Tables

In the previous section Naming Columns Distinctly from Attribute Names, we showed how a `Column` explicitly mapped to a class can have a different attribute name than the column. But what if we aren’t listing out `Column` objects explicitly, and instead are automating the production of `Table` objects using reflection (e.g. as described in Reflecting Database Objects)? In this case we can make use of the `DDLEvents.column_reflect()` event to intercept the production of `Column` objects and provide them with the `Column.key` of our choice:

    @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()

With the above event, the reflection of `Column` objects will be intercepted with our event that adds a new “.key” element, such as in a mapping as below:

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

If we want to qualify our event to only react for the specific `MetaData` object above, we can check for it in our event:

    @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()

## Naming All Columns with a Prefix

A quick approach to prefix column names, typically when mapping to an existing `Table` object, is to use `column_prefix`:

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

The above will place attribute names such as `_user_id`, `_user_name`, `_password` etc. on the mapped `User` class.

This approach is uncommon in modern usage. For dealing with reflected tables, a more flexible approach is to use that described in Automating Column Naming Schemes from Reflected Tables.

## Using column_property for column level options

Options can be specified when mapping a `Column` using the `column_property()` function. This function explicitly creates the `ColumnProperty` used by the `mapper()` to keep track of the `Column`; normally, the `mapper()` creates this automatically. Using `column_property()`, we can pass additional arguments about how we’d like the `Column` to be mapped. Below, we pass an option `active_history`, which specifies that a change to this column’s value should result in the former value being loaded first:

    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. This use case arises when mapping to a `join()` which has attributes which are equated to each other:

    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)

For more examples featuring this usage, see 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)

See examples of this usage at SQL Expressions as Mapped Attributes.

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

  Provide a column-level property for use with a Mapper.

  Column-based properties can normally be applied to the mapper’s `properties` dictionary using the `Column` element directly. Use this function when the given column is not directly present within the mapper’s selectable; examples include SQL expressions, functions, and scalar SELECT queries.

  Columns that aren’t present in the mapper’s selectable won’t be persisted by the mapper and are effectively “read-only” attributes.

  Parameters: | *cols – list of Column objects to be mapped. active_history=False – When `True`, indicates that the “previous” value for a scalar attribute should be loaded when replaced, if not already loaded. Normally, history tracking logic for simple non-primary-key scalar values only needs to be aware of the “new” value in order to perform a flush. This flag is available for applications that make use of `attributes.get_history()` or `Session.is_modified()` which also need to know the “previous” value of the attribute. 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. See also `deferred()`. doc – optional string that will be applied as the doc on the class-bound descriptor. expire_on_flush=True – Disable expiry on flush. A column_property() which refers to a SQL expression (and not a single table-bound column) is considered to be a “read only” property; populating it has no effect on the state of data, and it can only return database state. For this reason a column_property()’s value is expired whenever the parent object is involved in a flush, that is, has any kind of “dirty” state within a flush. Setting this parameter to `False` will have the effect of leaving any existing value present after the flush proceeds. Note however that the `Session` with default expiration settings still expires all attributes after a `Session.commit()` call, however. New in version 0.7.3. info – Optional data dictionary which will be populated into the `MapperProperty.info` attribute of this object. New in version 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. Deprecated. Please see `AttributeEvents`.

## Mapping a Subset of Table Columns

Sometimes, a `Table` object was made available using the reflection process described at Reflecting Database Objects to load the table’s structure from the database. For such a table that has lots of columns that don’t need to be referenced in the application, the `include_properties` or `exclude_properties` arguments can specify that only a subset of columns should be mapped. For example:

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

…will map the `User` class to the `user_table` table, only including the `user_id` and `user_name` columns - the rest are not referenced. Similarly:

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

…will map the `Address` class to the `address_table` table, including all columns present except `street`, `city`, `state`, and `zip`.

When this mapping is used, the columns that are not included will not be referenced in any SELECT statements emitted by `Query`, nor will there be any mapped attribute on the mapped class which represents the column; assigning an attribute of that name will have no effect beyond that of a normal Python attribute assignment.

In some cases, multiple columns may have the same name, such as when mapping to a join of two or more tables that share some column name. `include_properties` and `exclude_properties` can also accommodate `Column` objects to more accurately describe which columns should be included or excluded:

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

Note

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. This is because in the case of `default` and `update`, the `Column` object is still present on the underlying `Table`, thus allowing the default functions to take place when the ORM emits an INSERT or UPDATE, and in the case of `server_default` and `server_onupdate`, the relational database itself maintains these functions.