Mapping Table Columns
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 , 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:
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 object can be referenced directly:
class User(Base):
__table__ = user_table
id = user_table.c.user_id
name = user_table.c.user_name
The corresponding technique for an imperative mapping is to place the desired key in the mapper.properties
dictionary with the desired key:
mapper_registry.map_imperatively(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.
In the previous section , 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 objects explicitly, and instead are automating the production of Table
objects using reflection (e.g. as described in )? In this case we can make use of the DDLEvents.column_reflect()
event to intercept the production of objects and provide them with the Column.key
of our choice. The event is most easily associated with the MetaData
object that’s in use, such as below we use the one linked to the instance:
@event.listens_for(Base.metadata, "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:
The approach also works with the extension. See the section Intercepting Column Definitions for background.
See also
Intercepting Column Definitions - in the documentation
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
The above will place attribute names such as _user_id
, , _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 .
Options can be specified when mapping a Column
using the function. This function explicitly creates the ColumnProperty
used by the to keep track of the Column
; normally, the creates this automatically. Using column_property()
, we can pass additional arguments about how we’d like the 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)
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 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:
See examples of this usage at SQL Expressions as Mapped Attributes.
function sqlalchemy.orm.``column_property
(\columns, **kwargs*)
Provide a column-level property for use with a mapping.
Column-based properties can normally be applied to the mapper’s properties
dictionary using the 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.
The column_property()
function returns an instance of .
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 ofget_history()
or which also need to know the “previous” value of the attribute.comparator_factory – a class which extends
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 .
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 theSession
with default expiration settings still expires all attributes after a call, however.info – Optional data dictionary which will be populated into the
MapperProperty.info
attribute of this object.raiseload –
if True, indicates the column should raise an error when undeferred, rather than loading the value. This can be altered at query time by using the option with raiseload=False.
New in version 1.4.
See also
See also
- to map columns while including mapping options
Using column_property - to map SQL expressions
Sometimes, a 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 , 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