Mapper Configuration with Declarative

    The examples given at Table Configuration with Declarative illustrate mappings against table-bound columns; the mapping of an individual column to an ORM class attribute is represented internally by the construct. There are many other varieties of mapper properties, the most common being the relationship() construct. Other kinds of properties include synonyms to columns which are defined using the construct, SQL expressions that are defined using the column_property() construct, and deferred columns and SQL expressions which load only when accessed, defined using the construct.

    While an imperative mapping makes use of the dictionary to establish all the mapped class attributes, in the declarative mapping, these properties are all specified inline with the class definition, which in the case of a declarative table mapping are inline with the Column objects that will be used to generate a object.

    Working with the example mapping of User and Address, we may illustrate a declarative table mapping that includes not just Column objects but also relationships and SQL expressions:

    The above declarative table mapping features two tables, each with a referring to the other, as well as a simple SQL expression mapped by column_property(), and an additional that will be loaded on a “deferred” basis as defined by the deferred() construct. More documentation on these particular concepts may be found at , Using column_property, and .

    Properties may be specified with a declarative mapping as above using “hybrid table” style as well; the Column objects that are directly part of a table move into the definition but everything else, including composed SQL expressions, would still be inline with the class definition. Constructs that need to refer to a Column directly would reference it in terms of the object. To illustrate the above mapping using hybrid table style:

    1. # mapping attributes using declarative with imperative table
    2. # i.e. __table__
    3. from sqlalchemy import Table
    4. from sqlalchemy import Column, Integer, String, Text, ForeignKey
    5. from sqlalchemy.orm import column_property, relationship, deferred
    6. from sqlalchemy.orm import declarative_base
    7. Base = declarative_base()
    8. class User(Base):
    9. __table__ = Table(
    10. "user",
    11. Base.metadata,
    12. Column("id", Integer, primary_key=True),
    13. Column("name", String),
    14. Column("firstname", String(50)),
    15. Column("lastname", String(50))
    16. )
    17. fullname = column_property(__table__.c.firstname + " " + __table__.c.lastname)
    18. addresses = relationship("Address", back_populates="user")
    19. class Address(Base):
    20. "address",
    21. Column("id", Integer, primary_key=True),
    22. Column("user_id", ForeignKey("user.id")),
    23. Column("email_address", String),
    24. Column("address_statistics", Text)
    25. )
    26. address_statistics = deferred(__table__.c.address_statistics)
    27. user = relationship("User", back_populates="addresses")

    Things to note above:

    • The address Table contains a column called address_statistics, however we re-map this column under the same attribute name to be under the control of a construct.

    • With both declararative table and hybrid table mappings, when we define a ForeignKey construct, we always name the target table using the table name, and not the mapped class name.

    With all mapping forms, the mapping of the class is configured through parameters that become part of the object. The function which ultimately receives these arguments is the mapper() function, and are delivered to it from one of the front-facing mapping functions defined on the object.

    For the declarative form of mapping, mapper arguments are specified using the __mapper_args__ declarative class variable, which is a dictionary that is passed as keyword arguments to the mapper() function. Some examples:

    Version ID Column

    The and mapper.version_id_generator parameters:

    1. from datetime import datetime
    2. class Widget(Base):
    3. __tablename__ = 'widgets'
    4. id = Column(Integer, primary_key=True)
    5. timestamp = Column(DateTime, nullable=False)
    6. __mapper_args__ = {
    7. 'version_id_col': timestamp,
    8. 'version_id_generator': lambda v:datetime.now()
    9. }

    Single Table Inheritance

    The and mapper.polymorphic_identity parameters:

    The __mapper_args__ dictionary may be generated from a class-bound descriptor method rather than from a fixed dictionary by making use of the construct. The section Composing Mapped Hierarchies with Mixins discusses this concept further.

    See also

    The __declare_last__() hook allows definition of a class level function that is automatically called by the event, which occurs after mappings are assumed to be completed and the ‘configure’ step has finished:

    1. class MyClass(Base):
    2. @classmethod
    3. def __declare_last__(cls):
    4. ""
    5. # do something with mappings

    Like __declare_last__(), but is called at the beginning of mapper configuration via the MapperEvents.before_configured() event:

    1. class MyClass(Base):
    2. def __declare_first__(cls):
    3. ""
    4. # do something before mappings are configured

    New in version 0.9.3.

    __abstract__ causes declarative to skip the production of a table or mapper for the class entirely. A class can be added within a hierarchy in the same way as mixin (see ), allowing subclasses to extend just from the special class:

    One possible use of __abstract__ is to use a distinct MetaData for different bases:

    1. Base = declarative_base()
    2. class DefaultBase(Base):
    3. __abstract__ = True
    4. metadata = MetaData()
    5. class OtherBase(Base):
    6. __abstract__ = True
    7. metadata = MetaData()

    Above, classes which inherit from DefaultBase will use one as the registry of tables, and those which inherit from OtherBase will use a different one. The tables themselves can then be created perhaps within distinct databases:

    1. DefaultBase.metadata.create_all(some_engine)
    2. OtherBase.metadata.create_all(some_other_engine)

    Allows the callable / class used to generate a Table to be customized. This is a very open-ended hook that can allow special customizations to a that one generates here:

    The above mixin would cause all Table objects generated to include the prefix "my_", followed by the name normally specified using the __tablename__ attribute.

    1. class AutoTable(object):
    2. @declared_attr
    3. def __tablename__(cls):
    4. return cls.__name__
    5. @classmethod
    6. def __table_cls__(cls, *arg, **kw):
    7. for obj in arg[1:]:
    8. if (isinstance(obj, Column) and obj.primary_key) or \
    9. isinstance(obj, PrimaryKeyConstraint):
    10. return Table(*arg, **kw)
    11. return None
    12. class Person(AutoTable, Base):
    13. id = Column(Integer, primary_key=True)
    14. class Employee(Person):

    The above Employee class would be mapped as single-table inheritance against Person; the column would be added as a member of the Person table.