Non-Traditional Mappings

    In the example above, the join expresses columns for both the user and the address table. The user.id and address.user_id columns are equated by foreign key, so in the mapping they are defined as one attribute, AddressUser.id, using column_property() to indicate a specialized column mapping. Based on this part of the configuration, the mapping will copy new primary key values from user.id into the address.user_id column when a flush occurs.

    Additionally, the address.id column is mapped explicitly to an attribute named address_id. This is to disambiguate the mapping of the address.id column from the same-named AddressUser.id attribute, which here has been assigned to refer to the user table combined with the foreign key.

    The natural primary key of the above mapping is the composite of (user.id, address.id), as these are the primary key columns of the user and address table combined together. The identity of an AddressUser object will be in terms of these two values, and is represented from an AddressUser object as (AddressUser.id, AddressUser.address_id).

    When referring to the AddressUser.id column, most SQL expressions will make use of only the first column in the list of columns mapped, as the two columns are synonymous. However, for the special use case such as a GROUP BY expression where both columns must be referenced at the same time while making use of the proper context, that is, accommodating for aliases and similar, the accessor may be used:

    New in version 1.3.17: Added the Comparator.expressions accessor.

    A mapping against multiple tables as illustrated above supports persistence, that is, INSERT, UPDATE and DELETE of rows within the targeted tables. However, it does not support an operation that would UPDATE one table and perform INSERT or DELETE on others at the same time for one record. That is, if a record PtoQ is mapped to tables “p” and “q”, where it has a row based on a LEFT OUTER JOIN of “p” and “q”, if an UPDATE proceeds that is to alter data in the “q” table in an existing record, the row in “q” must exist; it won’t emit an INSERT if the primary key identity is already present. If the row does not exist, for most DBAPI drivers which support reporting the number of rows affected by an UPDATE, the ORM will fail to detect an updated row and raise an error; otherwise, the data would be silently ignored.

    A recipe to allow for an on-the-fly “insert” of the related row might make use of the .MapperEvents.before_update event and look like:

    where above, a row is INSERTed into the q_table table by creating an INSERT construct with , then executing it using the given Connection which is the same one being used to emit other SQL for the flush process. The user-supplied logic would have to detect that the LEFT OUTER JOIN from “p” to “q” does not have an entry for the “q” side.

    Similar to mapping against a join, a plain object can be used with a mapper as well. The example fragment below illustrates mapping a class called Customer to a which includes a join to a subquery:

    Above, the full row represented by customer_select will be all the columns of the customers table, in addition to those columns exposed by the subq subquery, which are order_count, highest_order, and customer_id. Mapping the Customer class to this selectable then creates a class which will contain those attributes.

    Note

    The practice of mapping to arbitrary SELECT statements, especially complex ones as above, is almost never needed; it necessarily tends to produce complex queries which are often less efficient than that which would be produced by direct query construction. The practice is to some degree based on the very early history of SQLAlchemy where the construct was meant to represent the primary querying interface; in modern usage, the Query object can be used to construct virtually any SELECT statement, including complex composites, and should be favored over the “map-to-selectable” approach.

    In modern SQLAlchemy, a particular class is mapped by only one so-called primary mapper at a time. This mapper is involved in three main areas of functionality: querying, persistence, and instrumentation of the mapped class. The rationale of the primary mapper relates to the fact that the modifies the class itself, not only persisting it towards a particular Table, but also attributes upon the class which are structured specifically according to the table metadata. It’s not possible for more than one mapper to be associated with a class in equal measure, since only one mapper can actually instrument the class.

    The concept of a “non-primary” mapper had existed for many versions of SQLAlchemy however as of version 1.3 this feature is deprecated. The one case where such a non-primary mapper is useful is when constructing a relationship to a class against an alternative selectable. This use case is now suited using the construct and is described at Relationship to Aliased Class.

    As far as the use case of a class that can actually be fully persisted to different tables under different scenarios, very early versions of SQLAlchemy offered a feature for this adapted from Hibernate, known as the “entity name” feature. However, this use case became infeasible within SQLAlchemy once the mapped class itself became the source of SQL expression construction; that is, the class’ attributes themselves link directly to mapped table columns. The feature was removed and replaced with a simple recipe-oriented approach to accomplishing this task without any ambiguity of instrumentation - to create new subclasses, each mapped individually. This pattern is now available as a recipe at .