testing instructions.
- orm
+ - The official name for the relation() function is now
+ relationship(), to eliminate confusion over the relational
+ algebra term. relation() however will remain available
+ in equal capacity for the foreseeable future. [ticket:1740]
+
- Fixed bug in session.rollback() which involved not removing
formerly "pending" objects from the session before
re-integrating "deleted" objects, typically occured with
* ``sqlalchemy.orm.attributes`` - logs certain instrumented attribute operations, such as triggered callables
* ``sqlalchemy.orm.mapper`` - logs Mapper configuration and operations
* ``sqlalchemy.orm.unitofwork`` - logs flush() operations, including dependency sort graphs and other operations
- * ``sqlalchemy.orm.strategies`` - logs relation loader operations (i.e. lazy and eager loads)
+ * ``sqlalchemy.orm.strategies`` - logs relationship loader operations (i.e. lazy and eager loads)
* ``sqlalchemy.orm.sync`` - logs synchronization of attributes from parent to child instances during a flush()
For example, to log SQL queries as well as unit of work debugging:
====================
Mapper Configuration
====================
-This section references most major configurational patterns involving the :func:`~sqlalchemy.orm.mapper` and :func:`~sqlalchemy.orm.relation` functions. It assumes you've worked through :ref:`ormtutorial_toplevel` and know how to construct and use rudimentary mappers and relations.
+This section references most major configurational patterns involving the :func:`~sqlalchemy.orm.mapper` and :func:`~sqlalchemy.orm.relationship` functions. It assumes you've worked through :ref:`ormtutorial_toplevel` and know how to construct and use rudimentary mappers and relationships.
Mapper Configuration
====================
~~~~~~~~~~~~~~~~~~
-A quick way to add a "validation" routine to an attribute is to use the :func:`~sqlalchemy.orm.validates` decorator. This is a shortcut for using the :class:`sqlalchemy.orm.util.Validator` attribute extension with individual column or relation based attributes. An attribute validator can raise an exception, halting the process of mutating the attribute's value, or can change the given value into something different. Validators, like all attribute extensions, are only called by normal userland code; they are not issued when the ORM is populating the object.
+A quick way to add a "validation" routine to an attribute is to use the :func:`~sqlalchemy.orm.validates` decorator. This is a shortcut for using the :class:`sqlalchemy.orm.util.Validator` attribute extension with individual column or relationship based attributes. An attribute validator can raise an exception, halting the process of mutating the attribute's value, or can change the given value into something different. Validators, like all attribute extensions, are only called by normal userland code; they are not issued when the ORM is populating the object.
.. sourcecode:: python+sql
>>> str(EmailAddress.email == 'SomeAddress@foo.com')
lower(addresses.email) = lower(:lower_1)
-The ``__clause_element__()`` method is provided by the base ``Comparator`` class in use, and represents the SQL element which best matches what this attribute represents. For a column-based attribute, it's the mapped column. For a composite attribute, it's a :class:`~sqlalchemy.sql.expression.ClauseList` consisting of each column represented. For a relation, it's the table mapped by the local mapper (not the remote mapper). ``__clause_element__()`` should be honored by the custom comparator class in most cases since the resulting element will be applied any translations which are in effect, such as the correctly aliased member when using an ``aliased()`` construct or certain :func:`~sqlalchemy.orm.query.Query.with_polymorphic` scenarios.
+The ``__clause_element__()`` method is provided by the base ``Comparator`` class in use, and represents the SQL element which best matches what this attribute represents. For a column-based attribute, it's the mapped column. For a composite attribute, it's a :class:`~sqlalchemy.sql.expression.ClauseList` consisting of each column represented. For a relationship, it's the table mapped by the local mapper (not the remote mapper). ``__clause_element__()`` should be honored by the custom comparator class in most cases since the resulting element will be applied any translations which are in effect, such as the correctly aliased member when using an ``aliased()`` construct or certain :func:`~sqlalchemy.orm.query.Query.with_polymorphic` scenarios.
There are four kinds of ``Comparator`` classes which may be subclassed, as according to the type of mapper property configured:
* :func:`~sqlalchemy.orm.column_property` attribute - ``sqlalchemy.orm.properties.ColumnProperty.Comparator``
* :func:`~sqlalchemy.orm.composite` attribute - ``sqlalchemy.orm.properties.CompositeProperty.Comparator``
- * :func:`~sqlalchemy.orm.relation` attribute - ``sqlalchemy.orm.properties.RelationProperty.Comparator``
+ * :func:`~sqlalchemy.orm.relationship` attribute - ``sqlalchemy.orm.properties.RelationshipProperty.Comparator``
* :func:`~sqlalchemy.orm.comparable_property` attribute - ``sqlalchemy.orm.interfaces.PropComparator``
When using :func:`~sqlalchemy.orm.comparable_property`, which is a mapper property that isn't tied to any column or mapped table, the ``__clause_element__()`` method of :class:`~sqlalchemy.orm.interfaces.PropComparator` should also be implemented.
-The ``comparator_factory`` argument is accepted by all ``MapperProperty``-producing functions: :func:`~sqlalchemy.orm.column_property`, :func:`~sqlalchemy.orm.composite`, :func:`~sqlalchemy.orm.comparable_property`, :func:`~sqlalchemy.orm.synonym`, :func:`~sqlalchemy.orm.relation`, :func:`~sqlalchemy.orm.backref`, :func:`~sqlalchemy.orm.deferred`, and :func:`~sqlalchemy.orm.dynamic_loader`.
+The ``comparator_factory`` argument is accepted by all ``MapperProperty``-producing functions: :func:`~sqlalchemy.orm.column_property`, :func:`~sqlalchemy.orm.composite`, :func:`~sqlalchemy.orm.comparable_property`, :func:`~sqlalchemy.orm.synonym`, :func:`~sqlalchemy.orm.relationship`, :func:`~sqlalchemy.orm.backref`, :func:`~sqlalchemy.orm.deferred`, and :func:`~sqlalchemy.orm.dynamic_loader`.
Composite Column Types
-----------------------
The ORM does not generate ordering for any query unless explicitly configured.
-The "default" ordering for a collection, which applies to list-based collections, can be configured using the ``order_by`` keyword argument on :func:`~sqlalchemy.orm.relation`::
+The "default" ordering for a collection, which applies to list-based collections, can be configured using the ``order_by`` keyword argument on :func:`~sqlalchemy.orm.relationship`::
mapper(Address, addresses_table)
# order address objects by address id
mapper(User, users_table, properties={
- 'addresses': relation(Address, order_by=addresses_table.c.address_id)
+ 'addresses': relationship(Address, order_by=addresses_table.c.address_id)
})
-Note that when using eager loaders with relations, the tables used by the eager load's join are anonymously aliased. You can only order by these columns if you specify it at the :func:`~sqlalchemy.orm.relation` level. To control ordering at the query level based on a related table, you ``join()`` to that relation, then order by it::
+Note that when using eager loaders with relationships, the tables used by the eager load's join are anonymously aliased. You can only order by these columns if you specify it at the :func:`~sqlalchemy.orm.relationship` level. To control ordering at the query level based on a related table, you ``join()`` to that relationship, then order by it::
session.query(User).join('addresses').order_by(Address.street)
The table also has a column called ``type``. It is strongly advised in both single- and joined- table inheritance scenarios that the root table contains a column whose sole purpose is that of the **discriminator**; it stores a value which indicates the type of object represented within the row. The column may be of any desired datatype. While there are some "tricks" to work around the requirement that there be a discriminator column, they are more complicated to configure when one wishes to load polymorphically.
-Next we define individual tables for each of ``Engineer`` and ``Manager``, which contain columns that represent the attributes unique to the subclass they represent. Each table also must contain a primary key column (or columns), and in most cases a foreign key reference to the parent table. It is standard practice that the same column is used for both of these roles, and that the column is also named the same as that of the parent table. However this is optional in SQLAlchemy; separate columns may be used for primary key and parent-relation, the column may be named differently than that of the parent, and even a custom join condition can be specified between parent and child tables instead of using a foreign key::
+Next we define individual tables for each of ``Engineer`` and ``Manager``, which contain columns that represent the attributes unique to the subclass they represent. Each table also must contain a primary key column (or columns), and in most cases a foreign key reference to the parent table. It is standard practice that the same column is used for both of these roles, and that the column is also named the same as that of the parent table. However this is optional in SQLAlchemy; separate columns may be used for primary key and parent-relationship, the column may be named differently than that of the parent, and even a custom join condition can be specified between parent and child tables instead of using a foreign key::
engineers = Table('engineers', metadata,
Column('employee_id', Integer, ForeignKey('employees.employee_id'), primary_key=True),
Creating Joins to Specific Subtypes
++++++++++++++++++++++++++++++++++++
-The :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type` method is a helper which allows the construction of joins along :func:`~sqlalchemy.orm.relation` paths while narrowing the criterion to specific subclasses. Suppose the ``employees`` table represents a collection of employees which are associated with a ``Company`` object. We'll add a ``company_id`` column to the ``employees`` table and a new table ``companies``:
+The :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type` method is a helper which allows the construction of joins along :func:`~sqlalchemy.orm.relationship` paths while narrowing the criterion to specific subclasses. Suppose the ``employees`` table represents a collection of employees which are associated with a ``Company`` object. We'll add a ``company_id`` column to the ``employees`` table and a new table ``companies``:
.. sourcecode:: python+sql
pass
mapper(Company, companies, properties={
- 'employees': relation(Employee)
+ 'employees': relationship(Employee)
})
-When querying from ``Company`` onto the ``Employee`` relation, the ``join()`` method as well as the ``any()`` and ``has()`` operators will create a join from ``companies`` to ``employees``, without including ``engineers`` or ``managers`` in the mix. If we wish to have criterion which is specifically against the ``Engineer`` class, we can tell those methods to join or subquery against the joined table representing the subclass using the :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type` operator:
+When querying from ``Company`` onto the ``Employee`` relationship, the ``join()`` method as well as the ``any()`` and ``has()`` operators will create a join from ``companies`` to ``employees``, without including ``engineers`` or ``managers`` in the mix. If we wish to have criterion which is specifically against the ``Engineer`` class, we can tell those methods to join or subquery against the joined table representing the subclass using the :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type` operator:
.. sourcecode:: python+sql
) AS pjoin
[]
-Using Relations with Inheritance
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Using Relationships with Inheritance
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Both joined-table and single table inheritance scenarios produce mappings which are usable in :func:`~sqlalchemy.orm.relation` functions; that is, it's possible to map a parent object to a child object which is polymorphic. Similarly, inheriting mappers can have :func:`~sqlalchemy.orm.relation` objects of their own at any level, which are inherited to each child class. The only requirement for relations is that there is a table relationship between parent and child. An example is the following modification to the joined table inheritance example, which sets a bi-directional relationship between ``Employee`` and ``Company``:
+Both joined-table and single table inheritance scenarios produce mappings which are usable in :func:`~sqlalchemy.orm.relationship` functions; that is, it's possible to map a parent object to a child object which is polymorphic. Similarly, inheriting mappers can have :func:`~sqlalchemy.orm.relationship` objects of their own at any level, which are inherited to each child class. The only requirement for relationships is that there is a table relationship between parent and child. An example is the following modification to the joined table inheritance example, which sets a bi-directional relationship between ``Employee`` and ``Company``:
.. sourcecode:: python+sql
pass
mapper(Company, companies, properties={
- 'employees': relation(Employee, backref='company')
+ 'employees': relationship(Employee, backref='company')
})
SQLAlchemy has a lot of experience in this area; the optimized "outer join" approach can be used freely for parent and child relationships, eager loads are fully useable, :func:`~sqlalchemy.orm.aliased` objects and other techniques are fully supported as well.
-In a concrete inheritance scenario, mapping relations is more difficult since the distinct classes do not share a table. In this case, you *can* establish a relationship from parent to child if a join condition can be constructed from parent to child, if each child table contains a foreign key to the parent:
+In a concrete inheritance scenario, mapping relationships is more difficult since the distinct classes do not share a table. In this case, you *can* establish a relationship from parent to child if a join condition can be constructed from parent to child, if each child table contains a foreign key to the parent:
.. sourcecode:: python+sql
mapper(Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity='manager')
mapper(Engineer, engineers_table, inherits=employee_mapper, concrete=True, polymorphic_identity='engineer')
mapper(Company, companies, properties={
- 'employees': relation(Employee)
+ 'employees': relationship(Employee)
})
-The big limitation with concrete table inheritance is that :func:`~sqlalchemy.orm.relation` objects placed on each concrete mapper do **not** propagate to child mappers. If you want to have the same :func:`~sqlalchemy.orm.relation` objects set up on all concrete mappers, they must be configured manually on each. To configure back references in such a configuration the ``back_populates`` keyword may be used instead of ``backref``, such as below where both ``A(object)`` and ``B(A)`` bidirectionally reference ``C``::
+The big limitation with concrete table inheritance is that :func:`~sqlalchemy.orm.relationship` objects placed on each concrete mapper do **not** propagate to child mappers. If you want to have the same :func:`~sqlalchemy.orm.relationship` objects set up on all concrete mappers, they must be configured manually on each. To configure back references in such a configuration the ``back_populates`` keyword may be used instead of ``backref``, such as below where both ``A(object)`` and ``B(A)`` bidirectionally reference ``C``::
ajoin = polymorphic_union({
'a':a_table,
mapper(A, a_table, with_polymorphic=('*', ajoin),
polymorphic_on=ajoin.c.type, polymorphic_identity='a',
properties={
- 'some_c':relation(C, back_populates='many_a')
+ 'some_c':relationship(C, back_populates='many_a')
})
mapper(B, b_table,inherits=A, concrete=True,
polymorphic_identity='b',
properties={
- 'some_c':relation(C, back_populates='many_a')
+ 'some_c':relationship(C, back_populates='many_a')
})
mapper(C, c_table, properties={
- 'many_a':relation(A, collection_class=set, back_populates='some_c'),
+ 'many_a':relationship(A, collection_class=set, back_populates='some_c'),
})
Multiple Mappers for One Class
-------------------------------
-The first mapper created for a certain class is known as that class's "primary mapper." Other mappers can be created as well on the "load side" - these are called **secondary mappers**. This is a mapper that must be constructed with the keyword argument ``non_primary=True``, and represents a load-only mapper. Objects that are loaded with a secondary mapper will have their save operation processed by the primary mapper. It is also invalid to add new :func:`~sqlalchemy.orm.relation` objects to a non-primary mapper. To use this mapper with the Session, specify it to the :class:`~sqlalchemy.orm.session.Session.query` method:
+The first mapper created for a certain class is known as that class's "primary mapper." Other mappers can be created as well on the "load side" - these are called **secondary mappers**. This is a mapper that must be constructed with the keyword argument ``non_primary=True``, and represents a load-only mapper. Objects that are loaded with a secondary mapper will have their save operation processed by the primary mapper. It is also invalid to add new :func:`~sqlalchemy.orm.relationship` objects to a non-primary mapper. To use this mapper with the Session, specify it to the :class:`~sqlalchemy.orm.session.Session.query` method:
example:
# select
result = session.query(othermapper).select()
-The "non primary mapper" is a rarely needed feature of SQLAlchemy; in most cases, the :class:`~sqlalchemy.orm.query.Query` object can produce any kind of query that's desired. It's recommended that a straight :class:`~sqlalchemy.orm.query.Query` be used in place of a non-primary mapper unless the mapper approach is absolutely needed. Current use cases for the "non primary mapper" are when you want to map the class to a particular select statement or view to which additional query criterion can be added, and for when the particular mapped select statement or view is to be placed in a :func:`~sqlalchemy.orm.relation` of a parent mapper.
+The "non primary mapper" is a rarely needed feature of SQLAlchemy; in most cases, the :class:`~sqlalchemy.orm.query.Query` object can produce any kind of query that's desired. It's recommended that a straight :class:`~sqlalchemy.orm.query.Query` be used in place of a non-primary mapper unless the mapper approach is absolutely needed. Current use cases for the "non primary mapper" are when you want to map the class to a particular select statement or view to which additional query criterion can be added, and for when the particular mapped select statement or view is to be placed in a :func:`~sqlalchemy.orm.relationship` of a parent mapper.
Multiple "Persistence" Mappers for One Class
---------------------------------------------
m = mapper(User, users_table, extension=[ext1, ext2, ext3])
-.. _advdatamapping_relation:
+.. _advdatamapping_relationship:
-Relation Configuration
-=======================
+Relationship Configuration
+==========================
Basic Relational Patterns
--------------------------
pass
mapper(Parent, parent_table, properties={
- 'children': relation(Child)
+ 'children': relationship(Child)
})
mapper(Child, child_table)
.. sourcecode:: python+sql
mapper(Parent, parent_table, properties={
- 'children': relation(Child, backref='parent')
+ 'children': relationship(Child, backref='parent')
})
mapper(Child, child_table)
pass
mapper(Parent, parent_table, properties={
- 'child': relation(Child)
+ 'child': relationship(Child)
})
mapper(Child, child_table)
.. sourcecode:: python+sql
mapper(Parent, parent_table, properties={
- 'child': relation(Child, uselist=False, backref='parent')
+ 'child': relationship(Child, uselist=False, backref='parent')
})
Or to turn many-to-one into one-to-one:
.. sourcecode:: python+sql
mapper(Parent, parent_table, properties={
- 'child': relation(Child, backref=backref('parent', uselist=False))
+ 'child': relationship(Child, backref=backref('parent', uselist=False))
})
Many To Many
~~~~~~~~~~~~~
-Many to Many adds an association table between two classes. The association table is indicated by the ``secondary`` argument to :func:`~sqlalchemy.orm.relation`.
+Many to Many adds an association table between two classes. The association table is indicated by the ``secondary`` argument to :func:`~sqlalchemy.orm.relationship`.
.. sourcecode:: python+sql
)
mapper(Parent, left_table, properties={
- 'children': relation(Child, secondary=association_table)
+ 'children': relationship(Child, secondary=association_table)
})
mapper(Child, right_table)
-For a bi-directional relationship, both sides of the relation contain a collection by default, which can be modified on either side via the ``uselist`` flag to be scalar. The ``backref`` keyword will automatically use the same ``secondary`` argument for the reverse relation:
+For a bi-directional relationship, both sides of the relationship contain a collection by default, which can be modified on either side via the ``uselist`` flag to be scalar. The ``backref`` keyword will automatically use the same ``secondary`` argument for the reverse relationship:
.. sourcecode:: python+sql
mapper(Parent, left_table, properties={
- 'children': relation(Child, secondary=association_table, backref='parents')
+ 'children': relationship(Child, secondary=association_table, backref='parents')
})
.. _association_pattern:
Association Object
~~~~~~~~~~~~~~~~~~
-The association object pattern is a variant on many-to-many: it specifically is used when your association table contains additional columns beyond those which are foreign keys to the left and right tables. Instead of using the ``secondary`` argument, you map a new class directly to the association table. The left side of the relation references the association object via one-to-many, and the association class references the right side via many-to-one.
+The association object pattern is a variant on many-to-many: it specifically is used when your association table contains additional columns beyond those which are foreign keys to the left and right tables. Instead of using the ``secondary`` argument, you map a new class directly to the association table. The left side of the relationship references the association object via one-to-many, and the association class references the right side via many-to-one.
.. sourcecode:: python+sql
)
mapper(Parent, left_table, properties={
- 'children':relation(Association)
+ 'children':relationship(Association)
})
mapper(Association, association_table, properties={
- 'child':relation(Child)
+ 'child':relationship(Child)
})
mapper(Child, right_table)
-The bi-directional version adds backrefs to both relations:
+The bi-directional version adds backrefs to both relationships:
.. sourcecode:: python+sql
mapper(Parent, left_table, properties={
- 'children':relation(Association, backref="parent")
+ 'children':relationship(Association, backref="parent")
})
mapper(Association, association_table, properties={
- 'child':relation(Child, backref="parent_assocs")
+ 'child':relationship(Child, backref="parent_assocs")
})
mapper(Child, right_table)
To enhance the association object pattern such that direct access to the ``Association`` object is optional, SQLAlchemy provides the :ref:`associationproxy`.
-**Important Note**: it is strongly advised that the ``secondary`` table argument not be combined with the Association Object pattern, unless the :func:`~sqlalchemy.orm.relation` which contains the ``secondary`` argument is marked ``viewonly=True``. Otherwise, SQLAlchemy may persist conflicting data to the underlying association table since it is represented by two conflicting mappings. The Association Proxy pattern should be favored in the case where access to the underlying association data is only sometimes needed.
+**Important Note**: it is strongly advised that the ``secondary`` table argument not be combined with the Association Object pattern, unless the :func:`~sqlalchemy.orm.relationship` which contains the ``secondary`` argument is marked ``viewonly=True``. Otherwise, SQLAlchemy may persist conflicting data to the underlying association table since it is represented by two conflicting mappings. The Association Proxy pattern should be favored in the case where access to the underlying association data is only sometimes needed.
Adjacency List Relationships
-----------------------------
The **adjacency list** pattern is a common relational pattern whereby a table contains a foreign key reference to itself. This is the most common and simple way to represent hierarchical data in flat tables. The other way is the "nested sets" model, sometimes called "modified preorder". Despite what many online articles say about modified preorder, the adjacency list model is probably the most appropriate pattern for the large majority of hierarchical storage needs, for reasons of concurrency, reduced complexity, and that modified preorder has little advantage over an application which can fully load subtrees into the application space.
-SQLAlchemy commonly refers to an adjacency list relation as a **self-referential mapper**. In this example, we'll work with a single table called ``treenodes`` to represent a tree structure::
+SQLAlchemy commonly refers to an adjacency list relationship as a **self-referential mapper**. In this example, we'll work with a single table called ``treenodes`` to represent a tree structure::
nodes = Table('treenodes', metadata,
Column('id', Integer, primary_key=True),
5 3 subchild2
6 1 child3
-SQLAlchemy's ``mapper()`` configuration for a self-referential one-to-many relationship is exactly like a "normal" one-to-many relationship. When SQLAlchemy encounters the foreign key relation from ``treenodes`` to ``treenodes``, it assumes one-to-many unless told otherwise:
+SQLAlchemy's ``mapper()`` configuration for a self-referential one-to-many relationship is exactly like a "normal" one-to-many relationship. When SQLAlchemy encounters the foreign key relationship from ``treenodes`` to ``treenodes``, it assumes one-to-many unless told otherwise:
.. sourcecode:: python+sql
pass
mapper(Node, nodes, properties={
- 'children': relation(Node)
+ 'children': relationship(Node)
})
-To create a many-to-one relationship from child to parent, an extra indicator of the "remote side" is added, which contains the :class:`~sqlalchemy.schema.Column` object or objects indicating the remote side of the relation:
+To create a many-to-one relationship from child to parent, an extra indicator of the "remote side" is added, which contains the :class:`~sqlalchemy.schema.Column` object or objects indicating the remote side of the relationship:
.. sourcecode:: python+sql
mapper(Node, nodes, properties={
- 'parent': relation(Node, remote_side=[nodes.c.id])
+ 'parent': relationship(Node, remote_side=[nodes.c.id])
})
And the bi-directional version combines both:
.. sourcecode:: python+sql
mapper(Node, nodes, properties={
- 'children': relation(Node, backref=backref('parent', remote_side=[nodes.c.id]))
+ 'children': relationship(Node, backref=backref('parent', remote_side=[nodes.c.id]))
})
There are several examples included with SQLAlchemy illustrating self-referential strategies; these include :ref:`examples_adjacencylist` and :ref:`examples_xmlpersistence`.
Configuring Eager Loading
~~~~~~~~~~~~~~~~~~~~~~~~~~
-Eager loading of relations occurs using joins or outerjoins from parent to child table during a normal query operation, such that the parent and its child collection can be populated from a single SQL statement. SQLAlchemy's eager loading uses aliased tables in all cases when joining to related items, so it is compatible with self-referential joining. However, to use eager loading with a self-referential relation, SQLAlchemy needs to be told how many levels deep it should join; otherwise the eager load will not take place. This depth setting is configured via ``join_depth``:
+Eager loading of relationships occurs using joins or outerjoins from parent to child table during a normal query operation, such that the parent and its child collection can be populated from a single SQL statement. SQLAlchemy's eager loading uses aliased tables in all cases when joining to related items, so it is compatible with self-referential joining. However, to use eager loading with a self-referential relationship, SQLAlchemy needs to be told how many levels deep it should join; otherwise the eager load will not take place. This depth setting is configured via ``join_depth``:
.. sourcecode:: python+sql
mapper(Node, nodes, properties={
- 'children': relation(Node, lazy=False, join_depth=2)
+ 'children': relationship(Node, lazy=False, join_depth=2)
})
{sql}session.query(Node).all()
FROM treenodes LEFT OUTER JOIN treenodes AS treenodes_2 ON treenodes.id = treenodes_2.parent_id LEFT OUTER JOIN treenodes AS treenodes_1 ON treenodes_2.id = treenodes_1.parent_id
[]
-Specifying Alternate Join Conditions to relation()
----------------------------------------------------
+Specifying Alternate Join Conditions to relationship()
+------------------------------------------------------
-The :func:`~sqlalchemy.orm.relation` function uses the foreign key relationship between the parent and child tables to formulate the **primary join condition** between parent and child; in the case of a many-to-many relationship it also formulates the **secondary join condition**::
+The :func:`~sqlalchemy.orm.relationship` function uses the foreign key relationship between the parent and child tables to formulate the **primary join condition** between parent and child; in the case of a many-to-many relationship it also formulates the **secondary join condition**::
one to many/many to one:
------------------------
If you are working with a :class:`~sqlalchemy.schema.Table` which has no :class:`~sqlalchemy.schema.ForeignKey` objects on it (which can be the case when using reflected tables with MySQL), or if the join condition cannot be expressed by a simple foreign key relationship, use the ``primaryjoin`` and possibly ``secondaryjoin`` conditions to create the appropriate relationship.
-In this example we create a relation ``boston_addresses`` which will only load the user addresses with a city of "Boston":
+In this example we create a relationship ``boston_addresses`` which will only load the user addresses with a city of "Boston":
.. sourcecode:: python+sql
mapper(Address, addresses_table)
mapper(User, users_table, properties={
- 'boston_addresses': relation(Address, primaryjoin=
+ 'boston_addresses': relationship(Address, primaryjoin=
and_(users_table.c.user_id==addresses_table.c.user_id,
addresses_table.c.city=='Boston'))
})
pass
mapper(Keyword, keywords_table)
mapper(User, users_table, properties={
- 'keywords': relation(Keyword, secondary=userkeywords_table,
+ 'keywords': relationship(Keyword, secondary=userkeywords_table,
primaryjoin=users_table.c.user_id==userkeywords_table.c.user_id,
secondaryjoin=userkeywords_table.c.keyword_id==keywords_table.c.keyword_id
)
~~~~~~~~~~~~~~~~~~~~~~~~
-When using ``primaryjoin`` and ``secondaryjoin``, SQLAlchemy also needs to be aware of which columns in the relation reference the other. In most cases, a :class:`~sqlalchemy.schema.Table` construct will have :class:`~sqlalchemy.schema.ForeignKey` constructs which take care of this; however, in the case of reflected tables on a database that does not report FKs (like MySQL ISAM) or when using join conditions on columns that don't have foreign keys, the :func:`~sqlalchemy.orm.relation` needs to be told specifically which columns are "foreign" using the ``foreign_keys`` collection:
+When using ``primaryjoin`` and ``secondaryjoin``, SQLAlchemy also needs to be aware of which columns in the relationship reference the other. In most cases, a :class:`~sqlalchemy.schema.Table` construct will have :class:`~sqlalchemy.schema.ForeignKey` constructs which take care of this; however, in the case of reflected tables on a database that does not report FKs (like MySQL ISAM) or when using join conditions on columns that don't have foreign keys, the :func:`~sqlalchemy.orm.relationship` needs to be told specifically which columns are "foreign" using the ``foreign_keys`` collection:
.. sourcecode:: python+sql
mapper(Address, addresses_table)
mapper(User, users_table, properties={
- 'addresses': relation(Address, primaryjoin=
+ 'addresses': relationship(Address, primaryjoin=
users_table.c.user_id==addresses_table.c.user_id,
foreign_keys=[addresses_table.c.user_id])
})
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Very ambitious custom join conditions may fail to be directly persistable, and in some cases may not even load correctly. To remove the persistence part of the equation, use the flag ``viewonly=True`` on the :func:`~sqlalchemy.orm.relation`, which establishes it as a read-only attribute (data written to the collection will be ignored on flush()). However, in extreme cases, consider using a regular Python property in conjunction with :class:`~sqlalchemy.orm.query.Query` as follows:
+Very ambitious custom join conditions may fail to be directly persistable, and in some cases may not even load correctly. To remove the persistence part of the equation, use the flag ``viewonly=True`` on the :func:`~sqlalchemy.orm.relationship`, which establishes it as a read-only attribute (data written to the collection will be ignored on flush()). However, in extreme cases, consider using a regular Python property in conjunction with :class:`~sqlalchemy.orm.query.Query` as follows:
.. sourcecode:: python+sql
return object_session(self).query(Address).with_parent(self).filter(...).all()
addresses = property(_get_addresses)
-Multiple Relations against the Same Parent/Child
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Multiple Relationships against the Same Parent/Child
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Theres no restriction on how many times you can relate from parent to child. SQLAlchemy can usually figure out what you want, particularly if the join conditions are straightforward. Below we add a ``newyork_addresses`` attribute to complement the ``boston_addresses`` attribute:
.. sourcecode:: python+sql
mapper(User, users_table, properties={
- 'boston_addresses': relation(Address, primaryjoin=
+ 'boston_addresses': relationship(Address, primaryjoin=
and_(users_table.c.user_id==addresses_table.c.user_id,
addresses_table.c.city=='Boston')),
- 'newyork_addresses': relation(Address, primaryjoin=
+ 'newyork_addresses': relationship(Address, primaryjoin=
and_(users_table.c.user_id==addresses_table.c.user_id,
addresses_table.c.city=='New York')),
})
Rows that point to themselves / Mutually Dependent Rows
-------------------------------------------------------
-This is a very specific case where relation() must perform an INSERT and a second UPDATE in order to properly populate a row (and vice versa an UPDATE and DELETE in order to delete without violating foreign key constraints). The two use cases are:
+This is a very specific case where relationship() must perform an INSERT and a second UPDATE in order to properly populate a row (and vice versa an UPDATE and DELETE in order to delete without violating foreign key constraints). The two use cases are:
* A table contains a foreign key to itself, and a single row will have a foreign key value pointing to its own primary key.
* Two tables each contain a foreign key referencing the other table, with a row in each table referencing the other.
widget_id name favorite_entry_id entry_id name widget_id
1 'somewidget' 5 5 'someentry' 1
-In the first case, a row points to itself. Technically, a database that uses sequences such as PostgreSQL or Oracle can INSERT the row at once using a previously generated value, but databases which rely upon autoincrement-style primary key identifiers cannot. The :func:`~sqlalchemy.orm.relation` always assumes a "parent/child" model of row population during flush, so unless you are populating the primary key/foreign key columns directly, :func:`~sqlalchemy.orm.relation` needs to use two statements.
+In the first case, a row points to itself. Technically, a database that uses sequences such as PostgreSQL or Oracle can INSERT the row at once using a previously generated value, but databases which rely upon autoincrement-style primary key identifiers cannot. The :func:`~sqlalchemy.orm.relationship` always assumes a "parent/child" model of row population during flush, so unless you are populating the primary key/foreign key columns directly, :func:`~sqlalchemy.orm.relationship` needs to use two statements.
-In the second case, the "widget" row must be inserted before any referring "entry" rows, but then the "favorite_entry_id" column of that "widget" row cannot be set until the "entry" rows have been generated. In this case, it's typically impossible to insert the "widget" and "entry" rows using just two INSERT statements; an UPDATE must be performed in order to keep foreign key constraints fulfilled. The exception is if the foreign keys are configured as "deferred until commit" (a feature some databases support) and if the identifiers were populated manually (again essentially bypassing :func:`~sqlalchemy.orm.relation`).
+In the second case, the "widget" row must be inserted before any referring "entry" rows, but then the "favorite_entry_id" column of that "widget" row cannot be set until the "entry" rows have been generated. In this case, it's typically impossible to insert the "widget" and "entry" rows using just two INSERT statements; an UPDATE must be performed in order to keep foreign key constraints fulfilled. The exception is if the foreign keys are configured as "deferred until commit" (a feature some databases support) and if the identifiers were populated manually (again essentially bypassing :func:`~sqlalchemy.orm.relationship`).
-To enable the UPDATE after INSERT / UPDATE before DELETE behavior on :func:`~sqlalchemy.orm.relation`, use the ``post_update`` flag on *one* of the relations, preferably the many-to-one side::
+To enable the UPDATE after INSERT / UPDATE before DELETE behavior on :func:`~sqlalchemy.orm.relationship`, use the ``post_update`` flag on *one* of the relationships, preferably the many-to-one side::
mapper(Widget, widget, properties={
- 'entries':relation(Entry, primaryjoin=widget.c.widget_id==entry.c.widget_id),
- 'favorite_entry':relation(Entry, primaryjoin=widget.c.favorite_entry_id==entry.c.entry_id, post_update=True)
+ 'entries':relationship(Entry, primaryjoin=widget.c.widget_id==entry.c.widget_id),
+ 'favorite_entry':relationship(Entry, primaryjoin=widget.c.favorite_entry_id==entry.c.entry_id, post_update=True)
})
When a structure using the above mapping is flushed, the "widget" row will be INSERTed minus the "favorite_entry_id" value, then all the "entry" rows will be INSERTed referencing the parent "widget" row, and then an UPDATE statement will populate the "favorite_entry_id" column of the "widget" table (it's one row at a time for the time being).
.. sourcecode:: python+sql
mapper(Parent, properties={
- children = relation(Child)
+ children = relationship(Child)
})
parent = Parent()
parent.children.append(Child())
print parent.children[0]
-Collections are not limited to lists. Sets, mutable sequences and almost any other Python object that can act as a container can be used in place of the default list, by specifying the ``collection_class`` option on :func:`~sqlalchemy.orm.relation`.
+Collections are not limited to lists. Sets, mutable sequences and almost any other Python object that can act as a container can be used in place of the default list, by specifying the ``collection_class`` option on :func:`~sqlalchemy.orm.relationship`.
.. sourcecode:: python+sql
# use a set
mapper(Parent, properties={
- children = relation(Child, collection_class=set)
+ children = relationship(Child, collection_class=set)
})
parent = Parent()
mapper(Item, items_table, properties={
# key by column
- 'notes': relation(Note, collection_class=column_mapped_collection(notes_table.c.keyword)),
+ 'notes': relationship(Note, collection_class=column_mapped_collection(notes_table.c.keyword)),
# or named attribute
- 'notes2': relation(Note, collection_class=attribute_mapped_collection('keyword')),
+ 'notes2': relationship(Note, collection_class=attribute_mapped_collection('keyword')),
# or any callable
- 'notes3': relation(Note, collection_class=mapped_collection(lambda entity: entity.a + entity.b))
+ 'notes3': relationship(Note, collection_class=mapped_collection(lambda entity: entity.a + entity.b))
})
# ...
Many custom types and existing library classes can be used as a entity collection type as-is without further ado. However, it is important to note that the instrumentation process _will_ modify the type, adding decorators around methods automatically.
-The decorations are lightweight and no-op outside of relations, but they do add unneeded overhead when triggered elsewhere. When using a library class as a collection, it can be good practice to use the "trivial subclass" trick to restrict the decorations to just your usage in relations. For example:
+The decorations are lightweight and no-op outside of relationships, but they do add unneeded overhead when triggered elsewhere. When using a library class as a collection, it can be good practice to use the "trivial subclass" trick to restrict the decorations to just your usage in relationships. For example:
.. sourcecode:: python+sql
class MyAwesomeList(some.great.library.AwesomeList):
pass
- # ... relation(..., collection_class=MyAwesomeList)
+ # ... relationship(..., collection_class=MyAwesomeList)
The ORM uses this approach for built-ins, quietly substituting a trivial subclass when a ``list``, ``set`` or ``dict`` is used directly.
Configuring Loader Strategies: Lazy Loading, Eager Loading
-----------------------------------------------------------
-In the :ref:`ormtutorial_toplevel`, we introduced the concept of **Eager Loading**. We used an ``option`` in conjunction with the :class:`~sqlalchemy.orm.query.Query` object in order to indicate that a relation should be loaded at the same time as the parent, within a single SQL query:
+In the :ref:`ormtutorial_toplevel`, we introduced the concept of **Eager Loading**. We used an ``option`` in conjunction with the :class:`~sqlalchemy.orm.query.Query` object in order to indicate that a relationship should be loaded at the same time as the parent, within a single SQL query:
.. sourcecode:: python+sql
WHERE users.name = ?
['jack']
-By default, all inter-object relationships are **lazy loading**. The scalar or collection attribute associated with a :func:`~sqlalchemy.orm.relation` contains a trigger which fires the first time the attribute is accessed, which issues a SQL call at that point:
+By default, all inter-object relationships are **lazy loading**. The scalar or collection attribute associated with a :func:`~sqlalchemy.orm.relationship` contains a trigger which fires the first time the attribute is accessed, which issues a SQL call at that point:
.. sourcecode:: python+sql
[5]
{stop}[<Address(u'jack@google.com')>, <Address(u'j25@yahoo.com')>]
-The default **loader strategy** for any :func:`~sqlalchemy.orm.relation` is configured by the ``lazy`` keyword argument, which defaults to ``True``. Below we set it as ``False`` so that the ``children`` relation is eager loading:
+The default **loader strategy** for any :func:`~sqlalchemy.orm.relationship` is configured by the ``lazy`` keyword argument, which defaults to ``True``. Below we set it as ``False`` so that the ``children`` relationship is eager loading:
.. sourcecode:: python+sql
# eager load 'children' attribute
mapper(Parent, parent_table, properties={
- 'children': relation(Child, lazy=False)
+ 'children': relationship(Child, lazy=False)
})
The loader strategy can be changed from lazy to eager as well as eager to lazy using the :func:`~sqlalchemy.orm.eagerload` and :func:`~sqlalchemy.orm.lazyload` query options:
# set children to load eagerly
session.query(Parent).options(eagerload('children')).all()
-To reference a relation that is deeper than one level, separate the names by periods:
+To reference a relationship that is deeper than one level, separate the names by periods:
.. sourcecode:: python+sql
session.query(Parent).options(eagerload('foo.bar.bat')).all()
-When using dot-separated names with :func:`~sqlalchemy.orm.eagerload`, option applies **only** to the actual attribute named, and **not** its ancestors. For example, suppose a mapping from ``A`` to ``B`` to ``C``, where the relations, named ``atob`` and ``btoc``, are both lazy-loading. A statement like the following:
+When using dot-separated names with :func:`~sqlalchemy.orm.eagerload`, option applies **only** to the actual attribute named, and **not** its ancestors. For example, suppose a mapping from ``A`` to ``B`` to ``C``, where the relationships, named ``atob`` and ``btoc``, are both lazy-loading. A statement like the following:
.. sourcecode:: python+sql
# mapping is the users->addresses mapping
mapper(User, users_table, properties={
- 'addresses': relation(Address, addresses_table)
+ 'addresses': relationship(Address, addresses_table)
})
# define a query on USERS with an outer join to ADDRESSES
Working with Large Collections
-------------------------------
-The default behavior of :func:`~sqlalchemy.orm.relation` is to fully load the collection of items in, as according to the loading strategy of the relation. Additionally, the Session by default only knows how to delete objects which are actually present within the session. When a parent instance is marked for deletion and flushed, the Session loads its full list of child items in so that they may either be deleted as well, or have their foreign key value set to null; this is to avoid constraint violations. For large collections of child items, there are several strategies to bypass full loading of child items both at load time as well as deletion time.
+The default behavior of :func:`~sqlalchemy.orm.relationship` is to fully load the collection of items in, as according to the loading strategy of the relationship. Additionally, the Session by default only knows how to delete objects which are actually present within the session. When a parent instance is marked for deletion and flushed, the Session loads its full list of child items in so that they may either be deleted as well, or have their foreign key value set to null; this is to avoid constraint violations. For large collections of child items, there are several strategies to bypass full loading of child items both at load time as well as deletion time.
-Dynamic Relation Loaders
-~~~~~~~~~~~~~~~~~~~~~~~~~
+Dynamic Relationship Loaders
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The most useful by far is the :func:`~sqlalchemy.orm.dynamic_loader` relation. This is a variant of :func:`~sqlalchemy.orm.relation` which returns a :class:`~sqlalchemy.orm.query.Query` object in place of a collection when accessed. :func:`~sqlalchemy.orm.query.Query.filter` criterion may be applied as well as limits and offsets, either explicitly or via array slices:
+The most useful by far is the :func:`~sqlalchemy.orm.dynamic_loader` relationship. This is a variant of :func:`~sqlalchemy.orm.relationship` which returns a :class:`~sqlalchemy.orm.query.Query` object in place of a collection when accessed. :func:`~sqlalchemy.orm.query.Query.filter` criterion may be applied as well as limits and offsets, either explicitly or via array slices:
.. sourcecode:: python+sql
# apply array slices
posts = jack.posts[5:20]
-The dynamic relation supports limited write operations, via the ``append()`` and ``remove()`` methods. Since the read side of the dynamic relation always queries the database, changes to the underlying collection will not be visible until the data has been flushed:
+The dynamic relationship supports limited write operations, via the ``append()`` and ``remove()`` methods. Since the read side of the dynamic relationship always queries the database, changes to the underlying collection will not be visible until the data has been flushed:
.. sourcecode:: python+sql
jack.posts.append(Post('new post'))
-To place a dynamic relation on a backref, use ``lazy='dynamic'``:
+To place a dynamic relationship on a backref, use ``lazy='dynamic'``:
.. sourcecode:: python+sql
mapper(Post, posts_table, properties={
- 'user': relation(User, backref=backref('posts', lazy='dynamic'))
+ 'user': relationship(User, backref=backref('posts', lazy='dynamic'))
})
-Note that eager/lazy loading options cannot be used in conjunction dynamic relations at this time.
+Note that eager/lazy loading options cannot be used in conjunction dynamic relationships at this time.
Setting Noload
~~~~~~~~~~~~~~~
-The opposite of the dynamic relation is simply "noload", specified using ``lazy=None``:
+The opposite of the dynamic relationship is simply "noload", specified using ``lazy=None``:
.. sourcecode:: python+sql
mapper(MyClass, table, properties={
- 'children': relation(MyOtherClass, lazy=None)
+ 'children': relationship(MyOtherClass, lazy=None)
})
Above, the ``children`` collection is fully writeable, and changes to it will be persisted to the database as well as locally available for reading at the time they are added. However when instances of ``MyClass`` are freshly loaded from the database, the ``children`` collection stays empty.
mapper(MyOtherClass, myothertable)
mapper(MyClass, mytable, properties={
- 'children': relation(MyOtherClass, cascade="all, delete-orphan", passive_deletes=True)
+ 'children': relationship(MyOtherClass, cascade="all, delete-orphan", passive_deletes=True)
})
-When ``passive_deletes`` is applied, the ``children`` relation will not be loaded into memory when an instance of ``MyClass`` is marked for deletion. The ``cascade="all, delete-orphan"`` *will* take effect for instances of ``MyOtherClass`` which are currently present in the session; however for instances of ``MyOtherClass`` which are not loaded, SQLAlchemy assumes that "ON DELETE CASCADE" rules will ensure that those rows are deleted by the database and that no foreign key violation will occur.
+When ``passive_deletes`` is applied, the ``children`` relationship will not be loaded into memory when an instance of ``MyClass`` is marked for deletion. The ``cascade="all, delete-orphan"`` *will* take effect for instances of ``MyOtherClass`` which are currently present in the session; however for instances of ``MyOtherClass`` which are not loaded, SQLAlchemy assumes that "ON DELETE CASCADE" rules will ensure that those rows are deleted by the database and that no foreign key violation will occur.
Mutable Primary Keys / Update Cascades
---------------------------------------
pass
mapper(User, users, properties={
- 'addresses': relation(Address, passive_updates=False)
+ 'addresses': relationship(Address, passive_updates=False)
})
mapper(Address, addresses)
{stop}()
[(1, u'ed'), (1, u'fred'), (1, u'mary'), (1, u'wendy')]
-Building a Relation
-====================
+Building a Relationship
+=======================
Now let's consider a second table to be dealt with. Users in our system also can store any number of email addresses associated with their username. This implies a basic one to many association from the ``users_table`` to a new table which stores email addresses, which we will call ``addresses``. Using declarative, we define this table along with its mapped class, ``Address``:
.. sourcecode:: python+sql
>>> from sqlalchemy import ForeignKey
- >>> from sqlalchemy.orm import relation, backref
+ >>> from sqlalchemy.orm import relationship, backref
>>> class Address(Base):
... __tablename__ = 'addresses'
... id = Column(Integer, primary_key=True)
... email_address = Column(String, nullable=False)
... user_id = Column(Integer, ForeignKey('users.id'))
...
- ... user = relation(User, backref=backref('addresses', order_by=id))
+ ... user = relationship(User, backref=backref('addresses', order_by=id))
...
... def __init__(self, email_address):
... self.email_address = email_address
... def __repr__(self):
... return "<Address('%s')>" % self.email_address
-The above class introduces a **foreign key** constraint which references the ``users`` table. This defines for SQLAlchemy the relationship between the two tables at the database level. The relationship between the ``User`` and ``Address`` classes is defined separately using the :func:`~sqlalchemy.orm.relation()` function, which defines an attribute ``user`` to be placed on the ``Address`` class, as well as an ``addresses`` collection to be placed on the ``User`` class. Such a relation is known as a **bidirectional** relationship. Because of the placement of the foreign key, from ``Address`` to ``User`` it is **many to one**, and from ``User`` to ``Address`` it is **one to many**. SQLAlchemy is automatically aware of many-to-one/one-to-many based on foreign keys.
+The above class introduces a **foreign key** constraint which references the ``users`` table. This defines for SQLAlchemy the relationship between the two tables at the database level. The relationship between the ``User`` and ``Address`` classes is defined separately using the :func:`~sqlalchemy.orm.relationship()` function, which defines an attribute ``user`` to be placed on the ``Address`` class, as well as an ``addresses`` collection to be placed on the ``User`` class. Such a relationship is known as a **bidirectional** relationship. Because of the placement of the foreign key, from ``Address`` to ``User`` it is **many to one**, and from ``User`` to ``Address`` it is **one to many**. SQLAlchemy is automatically aware of many-to-one/one-to-many based on foreign keys.
-The :func:`~sqlalchemy.orm.relation()` function is extremely flexible, and could just have easily been defined on the ``User`` class:
+The :func:`~sqlalchemy.orm.relationship()` function is extremely flexible, and could just have easily been defined on the ``User`` class:
.. sourcecode:: python+sql
class User(Base):
# ....
- addresses = relation(Address, order_by=Address.id, backref="user")
+ addresses = relationship(Address, order_by=Address.id, backref="user")
-We are also free to not define a backref, and to define the :func:`~sqlalchemy.orm.relation()` only on one class and not the other. It is also possible to define two separate :func:`~sqlalchemy.orm.relation()` constructs for either direction, which is generally safe for many-to-one and one-to-many relations, but not for many-to-many relations.
+We are also free to not define a backref, and to define the :func:`~sqlalchemy.orm.relationship()` only on one class and not the other. It is also possible to define two separate :func:`~sqlalchemy.orm.relationship()` constructs for either direction, which is generally safe for many-to-one and one-to-many relationships, but not for many-to-many relationships.
-When using the ``declarative`` extension, :func:`~sqlalchemy.orm.relation()` gives us the option to use strings for most arguments that concern the target class, in the case that the target class has not yet been defined. This **only** works in conjunction with ``declarative``:
+When using the ``declarative`` extension, :func:`~sqlalchemy.orm.relationship()` gives us the option to use strings for most arguments that concern the target class, in the case that the target class has not yet been defined. This **only** works in conjunction with ``declarative``:
.. sourcecode:: python+sql
class User(Base):
....
- addresses = relation("Address", order_by="Address.id", backref="user")
+ addresses = relationship("Address", order_by="Address.id", backref="user")
When ``declarative`` is not in use, you typically define your :func:`~sqlalchemy.orm.mapper()` well after the target classes and :class:`~sqlalchemy.schema.Table` objects have been defined, so string expressions are not needed.
(5,)
{stop}[<Address('jack@google.com')>, <Address('j25@yahoo.com')>]
-When we accessed the ``addresses`` collection, SQL was suddenly issued. This is an example of a **lazy loading relation**. The ``addresses`` collection is now loaded and behaves just like an ordinary list.
+When we accessed the ``addresses`` collection, SQL was suddenly issued. This is an example of a **lazy loading relationship**. The ``addresses`` collection is now loaded and behaves just like an ordinary list.
If you want to reduce the number of queries (dramatically, in many cases), we can apply an **eager load** to the query operation, using the :func:`~sqlalchemy.orm.eagerload` function. This function is a **query option** that gives additional instructions to the query on how we would like it to load, in this case we'd like to indicate that we'd like ``addresses`` to load "eagerly". SQLAlchemy then constructs an outer join between the ``users`` and ``addresses`` tables, and loads them at once, populating the ``addresses`` collection on each ``User`` object if it's not already populated:
:meth:`~sqlalchemy.orm.query.Query.join` knows how to join between ``User`` and ``Address`` because there's only one foreign key between them. If there were no foreign keys, or several, :meth:`~sqlalchemy.orm.query.Query.join` works better when one of the following forms are used::
query.join((Address, User.id==Address.user_id)) # explicit condition (note the tuple)
- query.join(User.addresses) # specify relation from left to right
+ query.join(User.addresses) # specify relationship from left to right
query.join((Address, User.addresses)) # same, with explicit target
query.join('addresses') # same, using a string
()
{stop}jack
-The :class:`~sqlalchemy.orm.query.Query` features several operators which make usage of EXISTS automatically. Above, the statement can be expressed along the ``User.addresses`` relation using ``any()``:
+The :class:`~sqlalchemy.orm.query.Query` features several operators which make usage of EXISTS automatically. Above, the statement can be expressed along the ``User.addresses`` relationship using ``any()``:
.. sourcecode:: python+sql
('%google%',)
{stop}jack
-``has()`` is the same operator as ``any()`` for many-to-one relations (note the ``~`` operator here too, which means "NOT"):
+``has()`` is the same operator as ``any()`` for many-to-one relationships (note the ``~`` operator here too, which means "NOT"):
.. sourcecode:: python+sql
('jack',)
{stop}[]
-Common Relation Operators
+Common Relationship Operators
-------------------------
-Here's all the operators which build on relations:
+Here's all the operators which build on relationships:
* equals (used for many-to-one)::
query.filter(Address.user.has(name='ed'))
-* with_parent (used for any relation)::
+* with_parent (used for any relationship)::
session.query(Address).with_parent(someuser, 'addresses')
Configuring delete/delete-orphan Cascade
----------------------------------------
-We will configure **cascade** options on the ``User.addresses`` relation to change the behavior. While SQLAlchemy allows you to add new attributes and relations to mappings at any point in time, in this case the existing relation needs to be removed, so we need to tear down the mappings completely and start again. This is not a typical operation and is here just for illustrative purposes.
+We will configure **cascade** options on the ``User.addresses`` relationship to change the behavior. While SQLAlchemy allows you to add new attributes and relationships to mappings at any point in time, in this case the existing relationship needs to be removed, so we need to tear down the mappings completely and start again. This is not a typical operation and is here just for illustrative purposes.
Removing all ORM state is as follows:
>>> from sqlalchemy.orm import clear_mappers
>>> clear_mappers() # clear mappers
-Below, we use ``mapper()`` to reconfigure an ORM mapping for ``User`` and ``Address``, on our existing but currently un-mapped classes. The ``User.addresses`` relation now has ``delete, delete-orphan`` cascade on it, which indicates that DELETE operations will cascade to attached ``Address`` objects as well as ``Address`` objects which are removed from their parent:
+Below, we use ``mapper()`` to reconfigure an ORM mapping for ``User`` and ``Address``, on our existing but currently un-mapped classes. The ``User.addresses`` relationship now has ``delete, delete-orphan`` cascade on it, which indicates that DELETE operations will cascade to attached ``Address`` objects as well as ``Address`` objects which are removed from their parent:
.. sourcecode:: python+sql
>>> mapper(User, users_table, properties={ # doctest: +ELLIPSIS
- ... 'addresses':relation(Address, backref='user', cascade="all, delete, delete-orphan")
+ ... 'addresses':relationship(Address, backref='user', cascade="all, delete, delete-orphan")
... })
<Mapper at 0x...; User>
('jack@google.com', 'j25@yahoo.com')
{stop}0
-Building a Many To Many Relation
-=================================
+Building a Many To Many Relationship
+====================================
We're moving into the bonus round here, but lets show off a many-to-many relationship. We'll sneak in some other features too, just to take a tour. We'll make our application a blog application, where users can write ``BlogPost`` items, which have ``Keyword`` items associated with them.
... body = Column(Text)
...
... # many to many BlogPost<->Keyword
- ... keywords = relation('Keyword', secondary=post_keywords, backref='posts')
+ ... keywords = relationship('Keyword', secondary=post_keywords, backref='posts')
...
... def __init__(self, headline, body, author):
... self.author = author
... def __init__(self, keyword):
... self.keyword = keyword
-Above, the many-to-many relation is ``BlogPost.keywords``. The defining feature of a many-to-many relation is the ``secondary`` keyword argument which references a :class:`~sqlalchemy.schema.Table` object representing the association table. This table only contains columns which reference the two sides of the relation; if it has *any* other columns, such as its own primary key, or foreign keys to other tables, SQLAlchemy requires a different usage pattern called the "association object", described at :ref:`association_pattern`.
+Above, the many-to-many relationship is ``BlogPost.keywords``. The defining feature of a many-to-many relationship is the ``secondary`` keyword argument which references a :class:`~sqlalchemy.schema.Table` object representing the association table. This table only contains columns which reference the two sides of the relationship; if it has *any* other columns, such as its own primary key, or foreign keys to other tables, SQLAlchemy requires a different usage pattern called the "association object", described at :ref:`association_pattern`.
-The many-to-many relation is also bi-directional using the ``backref`` keyword. This is the one case where usage of ``backref`` is generally required, since if a separate ``posts`` relation were added to the ``Keyword`` entity, both relations would independently add and remove rows from the ``post_keywords`` table and produce conflicts.
+The many-to-many relationship is also bi-directional using the ``backref`` keyword. This is the one case where usage of ``backref`` is generally required, since if a separate ``posts`` relationship were added to the ``Keyword`` entity, both relationships would independently add and remove rows from the ``post_keywords`` table and produce conflicts.
-We would also like our ``BlogPost`` class to have an ``author`` field. We will add this as another bidirectional relationship, except one issue we'll have is that a single user might have lots of blog posts. When we access ``User.posts``, we'd like to be able to filter results further so as not to load the entire collection. For this we use a setting accepted by :func:`~sqlalchemy.orm.relation` called ``lazy='dynamic'``, which configures an alternate **loader strategy** on the attribute. To use it on the "reverse" side of a :func:`~sqlalchemy.orm.relation`, we use the :func:`~sqlalchemy.orm.backref` function:
+We would also like our ``BlogPost`` class to have an ``author`` field. We will add this as another bidirectional relationship, except one issue we'll have is that a single user might have lots of blog posts. When we access ``User.posts``, we'd like to be able to filter results further so as not to load the entire collection. For this we use a setting accepted by :func:`~sqlalchemy.orm.relationship` called ``lazy='dynamic'``, which configures an alternate **loader strategy** on the attribute. To use it on the "reverse" side of a :func:`~sqlalchemy.orm.relationship`, we use the :func:`~sqlalchemy.orm.backref` function:
.. sourcecode:: python+sql
>>> from sqlalchemy.orm import backref
- >>> # "dynamic" loading relation to User
- >>> BlogPost.author = relation(User, backref=backref('posts', lazy='dynamic'))
+ >>> # "dynamic" loading relationship to User
+ >>> BlogPost.author = relationship(User, backref=backref('posts', lazy='dynamic'))
Create new tables:
(2, 'firstpost')
{stop}[BlogPost("Wendy's Blog Post", 'This is a test', <User('wendy','Wendy Williams', 'foobar')>)]
-Or we can use Wendy's own ``posts`` relation, which is a "dynamic" relation, to query straight from there:
+Or we can use Wendy's own ``posts`` relationship, which is a "dynamic" relationship, to query straight from there:
.. sourcecode:: python+sql
related objects or to greatly simplify access to associated objects in an
association relationship.
-Simplifying Relations
----------------------
+Simplifying Relationships
+-------------------------
Consider this "association object" mapping::
self.keyword = keyword
mapper(User, users_table, properties={
- 'kw': relation(Keyword, secondary=userkeywords_table)
+ 'kw': relationship(Keyword, secondary=userkeywords_table)
})
mapper(Keyword, keywords_table)
Above are three simple tables, modeling users, keywords and a many-to-many
relationship between the two. These ``Keyword`` objects are little more
-than a container for a name, and accessing them via the relation is
+than a container for a name, and accessing them via the relationship is
awkward::
user = User('jek')
print [keyword.keyword for keyword in user.kw]
# ['cheese inspector']
-With ``association_proxy`` you have a "view" of the relation that contains
+With ``association_proxy`` you have a "view" of the relationship that contains
just the ``.keyword`` of the related objects. The proxy is a Python
-property, and unlike the mapper relation, is defined in your class::
+property, and unlike the mapper relationship, is defined in your class::
from sqlalchemy.ext.associationproxy import association_proxy
def __init__(self, name):
self.name = name
- # proxy the 'keyword' attribute from the 'kw' relation
+ # proxy the 'keyword' attribute from the 'kw' relationship
keywords = association_proxy('kw', 'keyword')
# ...
values are added to the proxy, and modifying or removing an entry through
the proxy also affects the underlying collection.
- - The association proxy property is backed by a mapper-defined relation,
+ - The association proxy property is backed by a mapper-defined relationship,
either a collection or scalar.
- You can access and modify both the proxy and the backing
- relation. Changes in one are immediate in the other.
+ relationship. Changes in one are immediate in the other.
- The proxy acts like the type of the underlying collection. A list gets a
list-like proxy, a dict a dict-like proxy, and so on.
- - Multiple proxies for the same relation are fine.
+ - Multiple proxies for the same relationship are fine.
- - Proxies are lazy, and won't trigger a load of the backing relation until
+ - Proxies are lazy, and won't trigger a load of the backing relationship until
they are accessed.
- - The relation is inspected to determine the type of the related objects.
+ - The relationship is inspected to determine the type of the related objects.
- To construct new instances, the type is called with the value being
assigned, or key and value for dicts.
maps conveniently to the value being set through the proxy. A ``creator``
function could have been used instead if more flexibility was required.
-Because the proxies are backed by a regular relation collection, all of the
+Because the proxies are backed by a regular relationship collection, all of the
usual hooks and patterns for using collections are still in effect. The
most convenient behavior is the automatic setting of "parent"-type
relationships on assignment. In the example above, nothing special had to
be done to associate the Keyword to the User. Simply adding it to the
collection is sufficient.
-Simplifying Association Object Relations
-----------------------------------------
+Simplifying Association Object Relationships
+--------------------------------------------
Association proxies are also useful for keeping ``association objects`` out
the way during regular use. For example, the ``userkeywords`` table
might have a bunch of auditing columns that need to get updated when changes
are made- columns that are updated but seldom, if ever, accessed in your
application. A proxy can provide a very natural access pattern for the
-relation.
+relationship.
.. sourcecode:: python
mapper(User, users_table)
mapper(Keyword, keywords_table)
mapper(UserKeyword, userkeywords_table, properties={
- 'user': relation(User, backref='user_keywords'),
- 'keyword': relation(Keyword),
+ 'user': relationship(User, backref='user_keywords'),
+ 'keyword': relationship(Keyword),
})
user = User('log')
Above are three tables, modeling stocks, their brokers and the number of
shares of a stock held by each broker. This situation is quite different
from the association example above. ``shares`` is a *property of the
-relation*, an important one that we need to use all the time.
+relationship*, an important one that we need to use all the time.
For this example, it would be very convenient if ``Broker`` objects had a
dictionary collection that mapped ``Stock`` instances to the shares held for
mapper(Stock, stocks_table)
mapper(Broker, brokers_table, properties={
- 'by_stock': relation(Holding,
+ 'by_stock': relationship(Holding,
collection_class=attribute_mapped_collection('stock'))
})
mapper(Holding, holdings_table, properties={
- 'stock': relation(Stock),
- 'broker': relation(Broker)
+ 'stock': relationship(Stock),
+ 'broker': relationship(Broker)
})
-Above, we've set up the ``by_stock`` relation collection to act as a
+Above, we've set up the ``by_stock`` relationship collection to act as a
dictionary, using the ``.stock`` property of each Holding as a key.
Populating and accessing that dictionary manually is slightly inconvenient
:author: Jason Kirtland
-``orderinglist`` is a helper for mutable ordered relations. It will intercept
-list operations performed on a relation collection and automatically
+``orderinglist`` is a helper for mutable ordered relationships. It will intercept
+list operations performed on a relationship collection and automatically
synchronize changes in list position with an attribute on the related objects.
(See :ref:`advdatamapping_entitycollections` for more information on the general pattern.)
pass
mapper(Slide, slides_table, properties={
- 'bullets': relation(Bullet, order_by=[bullets_table.c.position])
+ 'bullets': relationship(Bullet, order_by=[bullets_table.c.position])
})
mapper(Bullet, bullets_table)
-The standard relation mapping will produce a list-like attribute on each Slide
+The standard relationship mapping will produce a list-like attribute on each Slide
containing all related Bullets, but coping with changes in ordering is totally
your responsibility. If you insert a Bullet into that list, there is no
magic- it won't have a position attribute unless you assign it it one, and
.. sourcecode:: python+sql
mapper(Slide, slides_table, properties={
- 'bullets': relation(Bullet,
+ 'bullets': relationship(Bullet,
collection_class=ordering_list('position'),
order_by=[bullets_table.c.position])
})
s.bullets[2].position
>>> 2
-Use the ``ordering_list`` function to set up the ``collection_class`` on relations
+Use the ``ordering_list`` function to set up the ``collection_class`` on relationships
(as in the mapper example above). This implementation depends on the list
-starting in the proper order, so be SURE to put an order_by on your relation.
+starting in the proper order, so be SURE to put an order_by on your relationship.
``ordering_list`` takes the name of the related object's ordering attribute as
an argument. By default, the zero-based integer index of the object's
database table or selectable available as attributes on the class.
**Mapper properties** allow you to customize and add additional
properties to your classes, for example making the results one-to-many
-join available as a Python list of :func:`related <relation>` objects.
+join available as a Python list of :func:`related <relationship>` objects.
Mapper properties are most commonly included in the :func:`mapper`
call::
mapper(Parent, properties={
- 'children': relation(Children)
+ 'children': relationship(Children)
}
.. autofunction:: backref
.. autofunction:: dynamic_loader
-.. autofunction:: relation
+.. autofunction:: relationship
.. autofunction:: synonym
The solution is to use proper cascading::
mapper(User, users_table, properties={
- 'addresses':relation(Address, cascade="all, delete, delete-orphan")
+ 'addresses':relationship(Address, cascade="all, delete, delete-orphan")
})
del user.addresses[1]
session.flush()
session.expire(obj1)
session.expire(obj2)
-:func:`~sqlalchemy.orm.session.Session.refresh` and :func:`~sqlalchemy.orm.session.Session.expire` also support being passed a list of individual attribute names in which to be refreshed. These names can reference any attribute, column-based or relation based::
+:func:`~sqlalchemy.orm.session.Session.refresh` and :func:`~sqlalchemy.orm.session.Session.expire` also support being passed a list of individual attribute names in which to be refreshed. These names can reference any attribute, column-based or relationship based::
# immediately re-load the attributes 'hello', 'world' on obj1, obj2
session.refresh(obj1, ['hello', 'world'])
Cascades
========
-Mappers support the concept of configurable *cascade* behavior on :func:`~sqlalchemy.orm.relation` constructs. This behavior controls how the Session should treat the instances that have a parent-child relationship with another instance that is operated upon by the Session. Cascade is indicated as a comma-separated list of string keywords, with the possible values ``all``, ``delete``, ``save-update``, ``refresh-expire``, ``merge``, ``expunge``, and ``delete-orphan``.
+Mappers support the concept of configurable *cascade* behavior on :func:`~sqlalchemy.orm.relationship` constructs. This behavior controls how the Session should treat the instances that have a parent-child relationship with another instance that is operated upon by the Session. Cascade is indicated as a comma-separated list of string keywords, with the possible values ``all``, ``delete``, ``save-update``, ``refresh-expire``, ``merge``, ``expunge``, and ``delete-orphan``.
-Cascading is configured by setting the ``cascade`` keyword argument on a :func:`~sqlalchemy.orm.relation`::
+Cascading is configured by setting the ``cascade`` keyword argument on a :func:`~sqlalchemy.orm.relationship`::
mapper(Order, order_table, properties={
- 'items' : relation(Item, items_table, cascade="all, delete-orphan"),
- 'customer' : relation(User, users_table, user_orders_table, cascade="save-update"),
+ 'items' : relationship(Item, items_table, cascade="all, delete-orphan"),
+ 'customer' : relationship(User, users_table, user_orders_table, cascade="save-update"),
})
-The above mapper specifies two relations, ``items`` and ``customer``. The ``items`` relationship specifies "all, delete-orphan" as its ``cascade`` value, indicating that all ``add``, ``merge``, ``expunge``, ``refresh`` ``delete`` and ``expire`` operations performed on a parent ``Order`` instance should also be performed on the child ``Item`` instances attached to it. The ``delete-orphan`` cascade value additionally indicates that if an ``Item`` instance is no longer associated with an ``Order``, it should also be deleted. The "all, delete-orphan" cascade argument allows a so-called *lifecycle* relationship between an ``Order`` and an ``Item`` object.
+The above mapper specifies two relationships, ``items`` and ``customer``. The ``items`` relationship specifies "all, delete-orphan" as its ``cascade`` value, indicating that all ``add``, ``merge``, ``expunge``, ``refresh`` ``delete`` and ``expire`` operations performed on a parent ``Order`` instance should also be performed on the child ``Item`` instances attached to it. The ``delete-orphan`` cascade value additionally indicates that if an ``Item`` instance is no longer associated with an ``Order``, it should also be deleted. The "all, delete-orphan" cascade argument allows a so-called *lifecycle* relationship between an ``Order`` and an ``Item`` object.
-The ``customer`` relationship specifies only the "save-update" cascade value, indicating most operations will not be cascaded from a parent ``Order`` instance to a child ``User`` instance except for the :func:`~sqlalchemy.orm.session.Session.add` operation. "save-update" cascade indicates that an :func:`~sqlalchemy.orm.session.Session.add` on the parent will cascade to all child items, and also that items added to a parent which is already present in the session will also be added. "save-update" cascade also cascades the *pending history* of a relation()-based attribute, meaning that objects which were removed from a scalar or collection attribute whose changes have not yet been flushed are also placed into the new session - this so that foreign key clear operations and deletions will take place (new in 0.6).
+The ``customer`` relationship specifies only the "save-update" cascade value, indicating most operations will not be cascaded from a parent ``Order`` instance to a child ``User`` instance except for the :func:`~sqlalchemy.orm.session.Session.add` operation. "save-update" cascade indicates that an :func:`~sqlalchemy.orm.session.Session.add` on the parent will cascade to all child items, and also that items added to a parent which is already present in the session will also be added. "save-update" cascade also cascades the *pending history* of a relationship()-based attribute, meaning that objects which were removed from a scalar or collection attribute whose changes have not yet been flushed are also placed into the new session - this so that foreign key clear operations and deletions will take place (new in 0.6).
-Note that the ``delete-orphan`` cascade only functions for relationships where the target object can have a single parent at a time, meaning it is only appropriate for one-to-one or one-to-many relationships. For a :func:`~sqlalchemy.orm.relation` which establishes one-to-one via a local foreign key, i.e. a many-to-one that stores only a single parent, or one-to-one/one-to-many via a "secondary" (association) table, a warning will be issued if ``delete-orphan`` is configured. To disable this warning, also specify the ``single_parent=True`` flag on the relationship, which constrains objects to allow attachment to only one parent at a time.
+Note that the ``delete-orphan`` cascade only functions for relationships where the target object can have a single parent at a time, meaning it is only appropriate for one-to-one or one-to-many relationships. For a :func:`~sqlalchemy.orm.relationship` which establishes one-to-one via a local foreign key, i.e. a many-to-one that stores only a single parent, or one-to-one/one-to-many via a "secondary" (association) table, a warning will be issued if ``delete-orphan`` is configured. To disable this warning, also specify the ``single_parent=True`` flag on the relationship, which constrains objects to allow attachment to only one parent at a time.
-The default value for ``cascade`` on :func:`~sqlalchemy.orm.relation` is ``save-update, merge``.
+The default value for ``cascade`` on :func:`~sqlalchemy.orm.relationship` is ``save-update, merge``.
.. _unitofwork_transaction:
Using Aliases
==============
-The alias corresponds to a "renamed" version of a table or arbitrary relation, which occurs anytime you say "SELECT .. FROM sometable AS someothername". The ``AS`` creates a new name for the table. Aliases are super important in SQL as they allow you to reference the same table more than once. Scenarios where you need to do this include when you self-join a table to itself, or more commonly when you need to join from a parent table to a child table multiple times. For example, we know that our user ``jack`` has two email addresses. How can we locate jack based on the combination of those two addresses? We need to join twice to it. Let's construct two distinct aliases for the ``addresses`` table and join:
+The alias corresponds to a "renamed" version of a table or arbitrary relationship, which occurs anytime you say "SELECT .. FROM sometable AS someothername". The ``AS`` creates a new name for the table. Aliases are super important in SQL as they allow you to reference the same table more than once. Scenarios where you need to do this include when you self-join a table to itself, or more commonly when you need to join from a parent table to a child table multiple times. For example, we know that our user ``jack`` has two email addresses. How can we locate jack based on the combination of those two addresses? We need to join twice to it. Let's construct two distinct aliases for the ``addresses`` table and join:
.. sourcecode:: pycon+sql
from sqlalchemy import MetaData, Table, Column, Sequence, ForeignKey,\
Integer, String, create_engine
-from sqlalchemy.orm import sessionmaker, mapper, relation, backref,\
+from sqlalchemy.orm import sessionmaker, mapper, relationship, backref,\
eagerload_all
from sqlalchemy.orm.collections import attribute_mapped_collection
mapper(TreeNode, tree_table, properties={
- 'children': relation(TreeNode,
+ 'children': relationship(TreeNode,
# cascade deletions
cascade="all",
from sqlalchemy import (create_engine, MetaData, Table, Column, Integer,
String, DateTime, Numeric, ForeignKey, and_)
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
# Uncomment these to watch database activity.
#import logging
self.price = price or item.price
mapper(Order, orders, properties={
- 'order_items': relation(OrderItem, cascade="all, delete-orphan",
+ 'order_items': relationship(OrderItem, cascade="all, delete-orphan",
backref='order')
})
mapper(Item, items)
mapper(OrderItem, orderitems, properties={
- 'item': relation(Item, lazy=False)
+ 'item': relationship(Item, lazy=False)
})
session = create_session()
from datetime import datetime
from sqlalchemy import (create_engine, MetaData, Table, Column, Integer,
String, DateTime, Float, ForeignKey, and_)
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from sqlalchemy.ext.associationproxy import AssociationProxy
engine = create_engine('sqlite://')
mapper(Order, orders, properties={
- 'itemassociations':relation(OrderItem, cascade="all, delete-orphan", lazy=False)
+ 'itemassociations':relationship(OrderItem, cascade="all, delete-orphan", lazy=False)
})
mapper(Item, items)
mapper(OrderItem, orderitems, properties={
- 'item':relation(Item, lazy=False)
+ 'item':relationship(Item, lazy=False)
})
session = create_session()
# specify that each Person's "addresses" collection comes from
# cache too
- q = q.options(RelationCache("default", "by_person", Person.addresses))
+ q = q.options(RelationshipCache("default", "by_person", Person.addresses))
# query
print q.all()
python examples/beaker_caching/helloworld.py
- python examples/beaker_caching/relation_caching.py
+ python examples/beaker_caching/relationship_caching.py
python examples/beaker_caching/advanced.py
helloworld.py - the basic idea.
- relation_caching.py - Illustrates how to add cache options on
- relation endpoints, so that lazyloads load from cache.
+ relationship_caching.py - Illustrates how to add cache options on
+ relationship endpoints, so that lazyloads load from cache.
advanced.py - Further examples of how to use FromCache. Combines
techniques from the first two scripts.
retrieves results in/from Beaker.
* FromCache - a query option that establishes caching
parameters on a Query
- * RelationCache - a variant of FromCache which is specific
+ * RelationshipCache - a variant of FromCache which is specific
to a query invoked during a lazy load.
* _params_from_query - extracts value parameters from
a Query.
session using Session.merge(load=False), which is a fast performing
method to ensure state is present.
- The FromCache and RelationCache mapper options below represent
+ The FromCache and RelationshipCache mapper options below represent
the "public" method of
configuring the "cache_region" and "cache_namespace" attributes.
- RelationCache has the ability to be invoked upon lazy loaders embedded
+ RelationshipCache has the ability to be invoked upon lazy loaders embedded
in an object graph.
"""
_set_cache_parameters(query, self.region, self.namespace, self.cache_key)
-class RelationCache(MapperOption):
+class RelationshipCache(MapperOption):
"""Specifies that a Query as called within a "lazy load"
should load results from a cache."""
propagate_to_loaders = True
def __init__(self, region, namespace, attribute):
- """Construct a new RelationCache.
+ """Construct a new RelationshipCache.
:param region: the cache region. Should be a
region configured in the Beaker CacheManager.
lexical structure.
:param attribute: A Class.attribute which
- indicates a particular class relation() whose
+ indicates a particular class relationship() whose
lazy loader should be pulled from the cache.
"""
self.region = region
self.namespace = namespace
- self._relation_options = {
+ self._relationship_options = {
( attribute.property.parent.class_, attribute.property.key ) : self
}
mapper, key = query._current_path[-2:]
for cls in mapper.class_.__mro__:
- if (cls, key) in self._relation_options:
- relation_option = self._relation_options[(cls, key)]
+ if (cls, key) in self._relationship_options:
+ relationship_option = self._relationship_options[(cls, key)]
_set_cache_parameters(
query,
- relation_option.region,
- relation_option.namespace,
+ relationship_option.region,
+ relationship_option.namespace,
None)
def and_(self, option):
- """Chain another RelationCache option to this one.
+ """Chain another RelationshipCache option to this one.
- While many RelationCache objects can be specified on a single
+ While many RelationshipCache objects can be specified on a single
Query separately, chaining them together allows for a more efficient
lookup during load.
"""
- self._relation_options.update(option._relation_options)
+ self._relationship_options.update(option._relationship_options)
return self
"""
from sqlalchemy import Column, Integer, String, ForeignKey
-from sqlalchemy.orm import relation
-from meta import Base, FromCache, Session, RelationCache
+from sqlalchemy.orm import relationship
+from meta import Base, FromCache, Session, RelationshipCache
class Country(Base):
__tablename__ = 'country'
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=False)
country_id = Column(Integer, ForeignKey('country.id'), nullable=False)
- country = relation(Country)
+ country = relationship(Country)
def __init__(self, name, country):
self.name = name
id = Column(Integer, primary_key=True)
code = Column(String(10), nullable=False)
city_id = Column(Integer, ForeignKey('city.id'), nullable=False)
- city = relation(City)
+ city = relationship(City)
@property
def country(self):
person_id = Column(Integer, ForeignKey('person.id'), nullable=False)
street = Column(String(200), nullable=False)
postal_code_id = Column(Integer, ForeignKey('postal_code.id'))
- postal_code = relation(PostalCode)
+ postal_code = relationship(PostalCode)
@property
def city(self):
id = Column(Integer, primary_key=True)
name = Column(String(100), nullable=False)
- addresses = relation(Address, collection_class=set)
+ addresses = relationship(Address, collection_class=set)
def __init__(self, name, *addresses):
self.name = name
def format_full(self):
return "\t".join([str(x) for x in [self] + list(self.addresses)])
-# Caching options. A set of three RelationCache options
+# Caching options. A set of three RelationshipCache options
# which can be applied to Query(), causing the "lazy load"
# of these attributes to be loaded from cache.
-cache_address_bits = RelationCache("default", "byid", PostalCode.city).\
+cache_address_bits = RelationshipCache("default", "byid", PostalCode.city).\
and_(
- RelationCache("default", "byid", City.country)
+ RelationshipCache("default", "byid", City.country)
).and_(
- RelationCache("default", "byid", Address.postal_code)
+ RelationshipCache("default", "byid", Address.postal_code)
)
-"""relation_caching.py
+"""relationship_caching.py
Load a set of Person and Address objects, specifying that
related PostalCode, City, Country objects should be pulled from long
print p.format_full()
-print "\n\nIf this was the first run of relation_caching.py, SQL was likely emitted to "\
+print "\n\nIf this was the first run of relationship_caching.py, SQL was likely emitted to "\
"load postal codes, cities, countries.\n"\
"If run a second time, only a single SQL statement will run - all "\
"related data is pulled from cache.\n"\
"""
from sqlalchemy import (create_engine, MetaData, Table, Column, Integer, Text,
ForeignKey)
-from sqlalchemy.orm import (mapper, relation, create_session,
+from sqlalchemy.orm import (mapper, relationship, create_session,
InstrumentationManager)
from sqlalchemy.orm.attributes import set_attribute, get_attribute, del_attribute, is_instrumented
pass
mapper(A, table1, properties={
- 'bs':relation(B)
+ 'bs':relationship(B)
})
mapper(B, table2)
if __name__ == '__main__':
from sqlalchemy import Column, Integer, String, ForeignKey
- from sqlalchemy.orm import relation
+ from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
class Base(object):
id = Column(Integer, primary_key=True)
data = Column(String(50))
related_id = Column(Integer, ForeignKey("related.id"))
- related = relation("Related", backref="mapped")
+ related = relationship("Related", backref="mapped")
def __str__(self):
return "MyMappedClass(data=%r)" % self.data
\r
from sqlalchemy.ext.declarative import declarative_base\r
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey\r
-from sqlalchemy.orm import sessionmaker, relation\r
+from sqlalchemy.orm import sessionmaker, relationship\r
\r
engine=create_engine('sqlite://', echo=True)\r
Base = declarative_base(engine)\r
__tablename__ = 'parent'\r
id = Column(Integer, primary_key=True)\r
name = Column(String(50))\r
- _collection = relation("Child", lazy="dynamic", cascade="all, delete-orphan")\r
+ _collection = relationship("Child", lazy="dynamic", cascade="all, delete-orphan")\r
\r
@property\r
def child_map(self):\r
################################# PART I - Imports/Coniguration ####################################
from sqlalchemy import (MetaData, Table, Column, Integer, String, ForeignKey,
Unicode, and_)
-from sqlalchemy.orm import mapper, relation, create_session, lazyload
+from sqlalchemy.orm import mapper, relationship, create_session, lazyload
import sys, os, StringIO, re
# setup mappers. Document will eagerly load a list of _Node objects.
mapper(Document, documents, properties={
- '_root':relation(_Node, lazy=False, cascade="all")
+ '_root':relationship(_Node, lazy=False, cascade="all")
})
mapper(_Node, elements, properties={
- 'children':relation(_Node, cascade="all"),
+ 'children':relationship(_Node, cascade="all"),
# eagerly load attributes
- 'attributes':relation(_Attribute, lazy=False, cascade="all, delete-orphan"),
+ 'attributes':relationship(_Attribute, lazy=False, cascade="all, delete-orphan"),
})
mapper(_Attribute, attributes)
################################# PART I - Imports/Configuration ###########################################
from sqlalchemy import (MetaData, Table, Column, Integer, String, ForeignKey,
Unicode, and_)
-from sqlalchemy.orm import mapper, relation, create_session, lazyload
+from sqlalchemy.orm import mapper, relationship, create_session, lazyload
import sys, os, StringIO, re
# they will be ordered in primary key/insert order, so that we can reconstruct
# an ElementTree structure from the list.
mapper(Document, documents, properties={
- '_nodes':relation(_Node, lazy=False, cascade="all, delete-orphan")
+ '_nodes':relationship(_Node, lazy=False, cascade="all, delete-orphan")
})
# the _Node objects change the way they load so that a list of _Nodes will organize
# themselves hierarchically using the ElementTreeMarshal. this depends on the ordering of
-# nodes being hierarchical as well; relation() always applies at least ROWID/primary key
+# nodes being hierarchical as well; relationship() always applies at least ROWID/primary key
# ordering to rows which will suffice.
mapper(_Node, elements, properties={
- 'children':relation(_Node, lazy=None), # doesnt load; used only for the save relationship
- 'attributes':relation(_Attribute, lazy=False, cascade="all, delete-orphan"), # eagerly load attributes
+ 'children':relationship(_Node, lazy=None), # doesnt load; used only for the save relationship
+ 'attributes':relationship(_Attribute, lazy=False, cascade="all, delete-orphan"), # eagerly load attributes
})
mapper(_Attribute, attributes)
"""a directed graph example."""
from sqlalchemy import MetaData, Table, Column, Integer, ForeignKey
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
import logging
logging.basicConfig()
mapper(Node, nodes)
mapper(Edge, edges, properties={
- 'lower_node':relation(Node,
+ 'lower_node':relationship(Node,
primaryjoin=edges.c.lower_id==nodes.c.nodeid, backref='lower_edges'),
- 'higher_node':relation(Node,
+ 'higher_node':relationship(Node,
primaryjoin=edges.c.higher_id==nodes.c.nodeid, backref='higher_edges')
}
)
from sqlalchemy import MetaData, Table, Column, Integer, String, ForeignKey
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
import sets
# this example illustrates a polymorphic load of two classes
mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager')
mapper(Company, companies, properties={
- 'employees': relation(Person, lazy=False, backref='company', cascade="all, delete-orphan")
+ 'employees': relationship(Person, lazy=False, backref='company', cascade="all, delete-orphan")
})
session = create_session()
from sqlalchemy import MetaData, Table, Column, Integer, String, ForeignKey
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
metadata = MetaData('sqlite://')
metadata.bind.echo = 'debug'
engineer_mapper = mapper(Engineer, inherits=person_mapper, polymorphic_identity='engineer')
mapper(Company, companies, properties={
- 'employees': relation(Person, lazy=True, backref='company')
+ 'employees': relationship(Person, lazy=True, backref='company')
})
session = create_session()
"""Large collection example.
-Illustrates the options to use with :func:`~sqlalchemy.orm.relation()` when the list of related objects is very large, including:
+Illustrates the options to use with :func:`~sqlalchemy.orm.relationship()` when the list of related objects is very large, including:
-* "dynamic" relations which query slices of data as accessed
+* "dynamic" relationships which query slices of data as accessed
* how to use ON DELETE CASCADE in conjunction with ``passive_deletes=True`` to greatly improve the performance of related collection deletion.
"""
from sqlalchemy import (MetaData, Table, Column, Integer, String, ForeignKey,
create_engine)
-from sqlalchemy.orm import (mapper, relation, sessionmaker)
+from sqlalchemy.orm import (mapper, relationship, sessionmaker)
meta = MetaData()
self.name = name
mapper(Organization, org_table, properties = {
- 'members' : relation(Member,
+ 'members' : relationship(Member,
# Organization.members will be a Query object - no loading
# of the entire collection occurs unless requested
lazy="dynamic",
"""
from sqlalchemy import MetaData, Table, Column, Integer, String, and_
-from sqlalchemy.orm import (mapper, relation, create_session, class_mapper,
+from sqlalchemy.orm import (mapper, relationship, create_session, class_mapper,
backref)
metadata = MetaData('sqlite://')
addresses.c.addressable_type == table.name
)
foreign_keys = [addresses.c.addressable_id]
- mapper.add_property(name, relation(
+ mapper.add_property(name, relationship(
Address,
primaryjoin=primaryjoin, uselist=uselist, foreign_keys=foreign_keys,
backref=backref('_backref_%s' % table.name, primaryjoin=list(table.primary_key)[0] == addresses.c.addressable_id, foreign_keys=foreign_keys)
"""
from sqlalchemy import MetaData, Table, Column, Integer, String, ForeignKey
-from sqlalchemy.orm import mapper, relation, create_session, class_mapper
+from sqlalchemy.orm import mapper, relationship, create_session, class_mapper
metadata = MetaData('sqlite://')
"""
mapper = class_mapper(cls)
table = mapper.local_table
- mapper.add_property('address_rel', relation(AddressAssoc, backref='_backref_%s' % table.name))
+ mapper.add_property('address_rel', relationship(AddressAssoc, backref='_backref_%s' % table.name))
if uselist:
# list based property decorator
mapper(Address, addresses)
mapper(AddressAssoc, address_associations, properties={
- 'addresses':relation(Address, backref='association'),
+ 'addresses':relationship(Address, backref='association'),
})
######
"""
from sqlalchemy import MetaData, Table, Column, Integer, String, ForeignKey
-from sqlalchemy.orm import mapper, relation, create_session, class_mapper
+from sqlalchemy.orm import mapper, relationship, create_session, class_mapper
metadata = MetaData('sqlite://')
mapper = class_mapper(cls)
table = mapper.local_table
- mapper.add_property(attr_name, relation(GenericAssoc, backref='_backref_%s' % table.name))
+ mapper.add_property(attr_name, relationship(GenericAssoc, backref='_backref_%s' % table.name))
if uselist:
# list based property decorator
setattr(cls, 'member', property(lambda self: getattr(self.association, '_backref_%s' % self.association.type)))
mapper(GenericAssoc, association_table, properties={
- 'targets':relation(cls, backref='association'),
+ 'targets':relationship(cls, backref='association'),
})
return interface
# step 1. imports
from sqlalchemy import (create_engine, MetaData, Table, Column, Integer,
String, ForeignKey, Float, DateTime)
-from sqlalchemy.orm import sessionmaker, mapper, relation
+from sqlalchemy.orm import sessionmaker, mapper, relationship
from sqlalchemy.orm.shard import ShardedSession
from sqlalchemy.sql import operators
from sqlalchemy import sql
# step 7. mappers
mapper(WeatherLocation, weather_locations, properties={
- 'reports':relation(Report, backref='location')
+ 'reports':relationship(Report, backref='location')
})
mapper(Report, weather_reports)
from sqlalchemy import (MetaData, Table, Column, Integer, Unicode,
ForeignKey, UnicodeText, and_, not_, or_, String, Boolean, cast, text,
null, case)
- from sqlalchemy.orm import mapper, relation, create_session
+ from sqlalchemy.orm import mapper, relationship, create_session
from sqlalchemy.orm.collections import attribute_mapped_collection
metadata = MetaData()
mapper(Animal, animals, properties={
- 'facts': relation(
+ 'facts': relationship(
AnimalFact, backref='animal',
collection_class=attribute_mapped_collection('key')),
})
_property_mapping:
A string, the name of the Python attribute holding a dict-based
- relation of _property_type instances.
+ relationship of _property_type instances.
Using the VerticalProperty class above as an example,::
_property_mapping = 'props'
mapper(MyObj, sometable, properties={
- 'props': relation(VerticalProperty,
+ 'props': relationship(VerticalProperty,
collection_class=attribute_mapped_collection('key'))})
- Dict-like access to MyObj is proxied through to the 'props' relation::
+ Dict-like access to MyObj is proxied through to the 'props' relationship::
myobj['key'] = 'value'
# ...is shorthand for:
if __name__ == '__main__':
from sqlalchemy import (MetaData, Table, Column, Integer, Unicode,
ForeignKey, UnicodeText, and_, not_)
- from sqlalchemy.orm import mapper, relation, create_session
+ from sqlalchemy.orm import mapper, relationship, create_session
from sqlalchemy.orm.collections import attribute_mapped_collection
metadata = MetaData()
mapper(Animal, animals, properties={
- 'facts': relation(
+ 'facts': relationship(
AnimalFact, backref='animal',
collection_class=attribute_mapped_collection('key')),
})
When using the SQLAlchemy ORM, the ORM has limited ability to manually issue
cascading updates - specify ForeignKey objects using the
"deferrable=True, initially='deferred'" keyword arguments,
-and specify "passive_updates=False" on each relation().
+and specify "passive_updates=False" on each relationship().
Oracle 8 Compatibility
----------------------
always in sync with *target_collection*, and mutations made to either
collection will be reflected in both.
- Implements a Python property representing a relation as a collection of
+ Implements a Python property representing a relationship as a collection of
simpler values. The proxied property will mimic the collection type of
- the target (list, dict or set), or, in the case of a one to one relation,
+ the target (list, dict or set), or, in the case of a one to one relationship,
a simple scalar value.
- :param target_collection: Name of the relation attribute we'll proxy to,
- usually created with :func:`~sqlalchemy.orm.relation`.
+ :param target_collection: Name of the relationship attribute we'll proxy to,
+ usually created with :func:`~sqlalchemy.orm.relationship`.
:param attr: Attribute on the associated instances we'll proxy for.
by this proxy property would look like [getattr(obj1, *attr*),
getattr(obj2, *attr*)]
- If the relation is one-to-one or otherwise uselist=False, then simply:
+ If the relationship is one-to-one or otherwise uselist=False, then simply:
getattr(obj, *attr*)
:param creator: optional.
If you want to construct instances differently, supply a *creator*
function that takes arguments as above and returns instances.
- For scalar relations, creator() will be called if the target is None.
+ For scalar relationships, creator() will be called if the target is None.
If the target is present, set operations are proxied to setattr() on the
associated object.
If you have an associated object with multiple attributes, you may set
up multiple association proxies mapping to different attributes. See
the unit tests for examples, and for examples of how creator() functions
- can be used to construct the scalar relation on-demand in this
+ can be used to construct the scalar relationship on-demand in this
situation.
:param \*\*kw: Passes along any other keyword arguments to
target_collection
Name of the collection we'll proxy to, usually created with
- 'relation()' in a mapper setup.
+ 'relationship()' in a mapper setup.
attr
Attribute on the collected instances we'll proxy for. For example,
sniffing the target collection. If your collection type can't be
determined by duck typing or you'd like to use a different
collection implementation, you may supply a factory function to
- produce those collections. Only applicable to non-scalar relations.
+ produce those collections. Only applicable to non-scalar relationships.
proxy_bulk_set
Optional, use with proxy_factory. See the _set() method for
lazy_collection
A callable returning a list-based collection of entities (usually an
- object attribute managed by a SQLAlchemy relation())
+ object attribute managed by a SQLAlchemy relationship())
creator
A function that creates new target entities. Given one parameter:
:func:`~sqlalchemy.orm.mapper()` definitions as appropriate::
SomeClass.data = Column('data', Unicode)
- SomeClass.related = relation(RelatedInfo)
+ SomeClass.related = relationship(RelatedInfo)
Classes which are mapped explicitly using
:func:`~sqlalchemy.orm.mapper()` can interact freely with declarative
mymetadata = MetaData()
Base = declarative_base(metadata=mymetadata)
-Configuring Relations
-=====================
+Configuring Relationships
+=========================
-Relations to other classes are done in the usual way, with the added
-feature that the class specified to :func:`~sqlalchemy.orm.relation()`
+Relationships to other classes are done in the usual way, with the added
+feature that the class specified to :func:`~sqlalchemy.orm.relationship()`
may be a string name. The "class registry" associated with ``Base``
is used at mapper compilation time to resolve the name into the actual
class object, which is expected to have been defined once the mapper
id = Column(Integer, primary_key=True)
name = Column(String(50))
- addresses = relation("Address", backref="user")
+ addresses = relationship("Address", backref="user")
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email = Column(String(50))
user_id = Column(Integer, ForeignKey('users.id'))
- user = relation(User, primaryjoin=user_id == User.id)
+ user = relationship(User, primaryjoin=user_id == User.id)
-In addition to the main argument for :func:`~sqlalchemy.orm.relation`,
+In addition to the main argument for :func:`~sqlalchemy.orm.relationship`,
other arguments which depend upon the columns present on an as-yet
undefined class may also be specified as strings. These strings are
evaluated as Python expressions. The full namespace available within
class User(Base):
# ....
- addresses = relation("Address",
+ addresses = relationship("Address",
order_by="desc(Address.email)",
primaryjoin="Address.user_id==User.id")
defined after all classes have been created. Just add them to the target
class after the fact::
- User.addresses = relation(Address,
+ User.addresses = relationship(Address,
primaryjoin=Address.user_id==User.id)
-Configuring Many-to-Many Relations
-==================================
+Configuring Many-to-Many Relationships
+======================================
There's nothing special about many-to-many with declarative. The
-``secondary`` argument to :func:`~sqlalchemy.orm.relation` still
+``secondary`` argument to :func:`~sqlalchemy.orm.relationship` still
requires a :class:`~sqlalchemy.schema.Table` object, not a declarative
class. The :class:`~sqlalchemy.schema.Table` should share the same
:class:`~sqlalchemy.schema.MetaData` object used by the declarative
class Author(Base):
__tablename__ = 'authors'
id = Column(Integer, primary_key=True)
- keywords = relation("Keyword", secondary=keywords)
+ keywords = relationship("Keyword", secondary=keywords)
You should generally **not** map a class and also specify its table in
-a many-to-many relation, since the ORM may issue duplicate INSERT and
+a many-to-many relationship, since the ORM may issue duplicate INSERT and
DELETE statements.
continue
if not isinstance(value, (Column, MapperProperty)):
continue
- prop = _deferred_relation(cls, value)
+ prop = _deferred_relationship(cls, value)
our_stuff[k] = prop
# set up attributes in the order they were created
cls.__table__.append_column(col)
cls.__mapper__.add_property(key, value)
elif isinstance(value, MapperProperty):
- cls.__mapper__.add_property(key, _deferred_relation(cls, value))
+ cls.__mapper__.add_property(key, _deferred_relationship(cls, value))
else:
type.__setattr__(cls, key, value)
else:
return getattr(self.cls, key)
-def _deferred_relation(cls, prop):
+def _deferred_relationship(cls, prop):
def resolve_arg(arg):
import sqlalchemy
except NameError, n:
raise exceptions.InvalidRequestError(
"When compiling mapper %s, expression %r failed to locate a name (%r). "
- "If this is a class name, consider adding this relation() to the %r "
+ "If this is a class name, consider adding this relationship() to the %r "
"class after both dependent classes have been defined." % (
prop.parent, arg, n.args[0], cls))
return return_cls
Only keys that are present as
attributes of the instance's class are allowed. These could be,
- for example, any mapped columns or relations.
+ for example, any mapped columns or relationships.
"""
for k in kwargs:
if not hasattr(type(self), k):
Defaults to
:func:`~sqlalchemy.ext.declarative._declarative_constructor`, an
__init__ implementation that assigns \**kwargs for declared
- fields and relations to an instance. If ``None`` is supplied,
+ fields and relationships to an instance. If ``None`` is supplied,
no __init__ will be provided and construction will fall back to
cls.__init__ by way of the normal Python semantics.
"""A custom list that manages index/position information for its children.
``orderinglist`` is a custom list collection implementation for mapped
-relations that keeps an arbitrary "position" attribute on contained objects in
+relationships that keeps an arbitrary "position" attribute on contained objects in
sync with each object's position in the Python list.
The collection acts just like a normal Python ``list``, with the added
behavior that as you manipulate the list (via ``insert``, ``pop``, assignment,
deletion, what have you), each of the objects it contains is updated as needed
-to reflect its position. This is very useful for managing ordered relations
+to reflect its position. This is very useful for managing ordered relationships
which have a user-defined, serialized order::
>>> from sqlalchemy import MetaData, Table, Column, Integer, String, ForeignKey
- >>> from sqlalchemy.orm import mapper, relation
+ >>> from sqlalchemy.orm import mapper, relationship
>>> from sqlalchemy.ext.orderinglist import ordering_list
A simple model of users their "top 10" things::
... self.blurb = blurb
...
>>> mapper(User, users, properties={
- ... 'topten': relation(Blurb, collection_class=ordering_list('position'),
+ ... 'topten': relationship(Blurb, collection_class=ordering_list('position'),
... order_by=[blurbs.c.position])})
<Mapper ...>
>>> mapper(Blurb, blurbs)
def ordering_list(attr, count_from=None, **kw):
"""Prepares an OrderingList factory for use in mapper definitions.
- Returns an object suitable for use as an argument to a Mapper relation's
+ Returns an object suitable for use as an argument to a Mapper relationship's
``collection_class`` option. Arguments are:
attr
See the module and __init__ documentation for more details. The
``ordering_list`` factory function is used to configure ``OrderingList``
- collections in ``mapper`` relation definitions.
+ collections in ``mapper`` relationship definitions.
"""
mapped objects.
This implementation relies on the list starting in the proper order,
- so be **sure** to put an ``order_by`` on your relation.
+ so be **sure** to put an ``order_by`` on your relationship.
ordering_attr
Name of the attribute that stores the object's order in the
- relation.
+ relationship.
ordering_func
Optional. A function that maps the position in the Python list to a
[u'name', u'email', u'password', u'classname', u'admin', u'loans_book_id', u'loans_user_name', u'loans_loan_date']
-Relations
-=========
+Relationships
+=============
-You can define relations on SqlSoup classes:
+You can define relationships on SqlSoup classes:
>>> db.users.relate('loans', db.loans)
[MappedUsers(name=u'Bhargan Basepair',email='basepair+nospam@example.edu',password=u'basepair',classname=None,admin=1)]
-relate can take any options that the relation function accepts in normal mapper definition:
+relate can take any options that the relationship function accepts in normal mapper definition:
>>> del db._cache['users']
>>> db.users.relate('loans', db.loans, order_by=db.loans.loan_date, cascade='all, delete-orphan')
from sqlalchemy import schema, sql
from sqlalchemy.engine.base import Engine
from sqlalchemy.orm import scoped_session, sessionmaker, mapper, \
- class_mapper, relation, session,\
+ class_mapper, relationship, session,\
object_session
from sqlalchemy.orm.interfaces import MapperExtension, EXT_CONTINUE
from sqlalchemy.exceptions import SQLAlchemyError, InvalidRequestError, ArgumentError
return o
def relate(cls, propname, *args, **kwargs):
- class_mapper(cls)._configure_property(propname, relation(*args, **kwargs))
+ class_mapper(cls)._configure_property(propname, relationship(*args, **kwargs))
def _is_outer_join(selectable):
if not isinstance(selectable, sql.Join):
ColumnProperty,
ComparableProperty,
CompositeProperty,
- RelationProperty,
+ RelationshipProperty,
PropertyLoader,
SynonymProperty,
)
'outerjoin',
'polymorphic_union',
'reconstructor',
+ 'relationship',
'relation',
'scoped_session',
'sessionmaker',
kwargs.setdefault('expire_on_commit', False)
return _Session(bind=bind, **kwargs)
-def relation(argument, secondary=None, **kwargs):
+def relationship(argument, secondary=None, **kwargs):
"""Provide a relationship of a primary Mapper to a secondary Mapper.
This corresponds to a parent-child or associative table relationship. The
- constructed class is an instance of :class:`RelationProperty`.
+ constructed class is an instance of :class:`RelationshipProperty`.
- A typical :func:`relation`::
+ A typical :func:`relationship`::
mapper(Parent, properties={
- 'children': relation(Children)
+ 'children': relationship(Children)
})
:param argument:
a class or :class:`Mapper` instance, representing the target of
- the relation.
+ the relationship.
:param secondary:
for a many-to-many relationship, specifies the intermediary
direction. The other property will be created automatically
when the mappers are configured. Can also be passed as a
:func:`backref` object to control the configuration of the
- new relation.
+ new relationship.
:param back_populates:
Takes a string name and has the same meaning as ``backref``,
except the complementing property is **not** created automatically,
and instead must be configured explicitly on the other mapper. The
complementing property should also indicate ``back_populates``
- to this relation to ensure proper functioning.
+ to this relationship to ensure proper functioning.
:param cascade:
a comma-separated list of cascade rules which determines how
be used in place of a plain list for storing elements.
:param comparator_factory:
- a class which extends :class:`RelationProperty.Comparator` which
+ a class which extends :class:`RelationshipProperty.Comparator` which
provides custom SQL clause generation for comparison operations.
:param extension:
this parameter should be used in conjunction with explicit
``primaryjoin`` and ``secondaryjoin`` (if needed) arguments, and
the columns within the ``foreign_keys`` list should be present
- within those join conditions. Normally, ``relation()`` will
+ within those join conditions. Normally, ``relationship()`` will
inspect the columns within the join conditions to determine
which columns are the "foreign key" columns, based on
information in the ``Table`` metadata. Use this argument when no
against related tables instead of an outer join. The purpose
of this option is strictly one of performance, as inner joins
generally perform better than outer joins. This flag can
- be set to ``True`` when the relation references an object
+ be set to ``True`` when the relationship references an object
via many-to-one using local foreign keys that are not nullable,
or when the reference is one-to-one or a collection that is
guaranteed to have one or at least one entry.
dependent rows. Note that with databases which enforce
referential integrity (i.e. PostgreSQL, MySQL with InnoDB tables),
ON UPDATE CASCADE is required for this operation. The
- relation() will update the value of the attribute on related
+ relationship() will update the value of the attribute on related
items which are locally present in the session during a flush.
When False, it is assumed that the database does not enforce
referential integrity and will not be issuing its own CASCADE
- operation for an update. The relation() will issue the
+ operation for an update. The relationship() will issue the
appropriate UPDATE statements to the database in response to the
change of a referenced key, and items locally present in the
session during a flush will also be refreshed.
This is used for many-to-one or many-to-many relationships that
should be treated either as one-to-one or one-to-many. Its
usage is optional unless delete-orphan cascade is also
- set on this relation(), in which case its required (new in 0.5.2).
+ set on this relationship(), in which case its required (new in 0.5.2).
:param uselist=(True|False):
a boolean that indicates if this property should be loaded as a
list or a scalar. In most cases, this value is determined
- automatically by ``relation()``, based on the type and direction
+ automatically by ``relationship()``, based on the type and direction
of the relationship - one to many forms a list, many to one
forms a scalar, many to many is a list. If a scalar is desired
where normally a list would be present, such as a bi-directional
one-to-one relationship, set uselist to False.
:param viewonly=False:
- when set to True, the relation is used only for loading objects
+ when set to True, the relationship is used only for loading objects
within the relationship, and has no effect on the unit-of-work
flush process. Relationships with viewonly can specify any kind of
join conditions to provide additional views of related objects
case, use an alternative method.
"""
- return RelationProperty(argument, secondary=secondary, **kwargs)
+ return RelationshipProperty(argument, secondary=secondary, **kwargs)
+def relation(*arg, **kw):
+ """A synonym for :func:`relationship`."""
+
+ return relationship(*arg, **kw)
+
def dynamic_loader(argument, secondary=None, primaryjoin=None,
secondaryjoin=None, foreign_keys=None, backref=None,
post_update=False, cascade=False, remote_side=None,
order_by=None, comparator_factory=None, query_class=None):
"""Construct a dynamically-loading mapper property.
- This property is similar to :func:`relation`, except read
+ This property is similar to :func:`relationship`, except read
operations return an active :class:`Query` object which reads from
the database when accessed. Items may be appended to the
attribute via ``append()``, or removed via ``remove()``; changes
However, no other Python list or collection mutation operations
are available.
- A subset of arguments available to :func:`relation` are available
+ A subset of arguments available to :func:`relationship` are available
here.
:param argument:
a class or :class:`Mapper` instance, representing the target of
- the relation.
+ the relationship.
:param secondary:
for a many-to-many relationship, specifies the intermediary
"""
from sqlalchemy.orm.dynamic import DynaLoader
- return RelationProperty(
+ return RelationshipProperty(
argument, secondary=secondary, primaryjoin=primaryjoin,
secondaryjoin=secondaryjoin, foreign_keys=foreign_keys, backref=backref,
post_update=post_update, cascade=cascade, remote_side=remote_side,
def backref(name, **kwargs):
"""Create a back reference with explicit arguments, which are the same
- arguments one can send to ``relation()``.
+ arguments one can send to ``relationship()``.
- Used with the `backref` keyword argument to ``relation()`` in
+ Used with the `backref` keyword argument to ``relationship()`` in
place of a string argument.
"""
dependent rows. Note that with databases which enforce
referential integrity (i.e. PostgreSQL, MySQL with InnoDB tables),
ON UPDATE CASCADE is required for this operation. The
- relation() will update the value of the attribute on related
+ relationship() will update the value of the attribute on related
items which are locally present in the session during a flush.
When False, it is assumed that the database does not enforce
referential integrity and will not be issuing its own CASCADE
- operation for an update. The relation() will issue the
+ operation for an update. The relationship() will issue the
appropriate UPDATE statements to the database in response to the
change of a referenced key, and items locally present in the
session during a flush will also be refreshed.
are expected and the database in use doesn't support CASCADE
(i.e. SQLite, MySQL MyISAM tables).
- Also see the passive_updates flag on :func:`relation()`.
+ Also see the passive_updates flag on :func:`relationship()`.
A future SQLAlchemy release will provide a "detect" feature for
this flag.
`name` refers to the name of the existing mapped property, which can be
any other ``MapperProperty`` including column-based properties and
- relations.
+ relationships.
If `map_column` is ``True``, an additional ``ColumnProperty`` is created
on the mapper automatically, using the synonym's name as the keyname of
query.options(eagerload_all(User.orders, Order.items, Item.keywords))
The keyword arguments accept a flag `innerjoin=True|False` which will
- override the value of the `innerjoin` flag specified on the relation().
+ override the value of the `innerjoin` flag specified on the relationship().
"""
innerjoin = kw.pop('innerjoin', None)
class InstrumentedList(list):
pass
-Collection classes can be specified in ``relation(collection_class=)`` as
+Collection classes can be specified in ``relationship(collection_class=)`` as
types or a function that returns an instance. Collection classes are
inspected and instrumented during the mapper compilation phase. The
collection_class callable will be executed once to produce a specimen
"""Relationship dependencies.
-Bridges the ``PropertyLoader`` (i.e. a ``relation()``) and the
-``UOWTransaction`` together to allow processing of relation()-based
+Bridges the ``PropertyLoader`` (i.e. a ``relationship()``) and the
+``UOWTransaction`` together to allow processing of relationship()-based
dependencies at flush time.
"""
self.key = prop.key
self.dependency_marker = MapperStub(self.parent, self.mapper, self.key)
if not self.prop.synchronize_pairs:
- raise sa_exc.ArgumentError("Can't build a DependencyProcessor for relation %s. "
+ raise sa_exc.ArgumentError("Can't build a DependencyProcessor for relationship %s. "
"No target attributes to populate between parent and child are present" % self.prop)
def _get_instrumented_attribute(self):
def _check_reverse_action(self, uowcommit, parent, child, action):
"""Determine if an action has been performed by the 'reverse' property of this property.
- this is used to ensure that only one side of a bidirectional relation
+ this is used to ensure that only one side of a bidirectional relationship
issues a certain operation for a parent/child pair.
"""
def _conditional_post_update(self, state, uowcommit, related):
"""Execute a post_update call.
- For relations that contain the post_update flag, an additional
+ For relationships that contain the post_update flag, an additional
``UPDATE`` statement may be associated after an ``INSERT`` or
before a ``DELETE`` in order to resolve circular row
dependencies.
return sync.source_modified(uowcommit, state, self.parent, self.prop.synchronize_pairs)
class DetectKeySwitch(DependencyProcessor):
- """a special DP that works for many-to-one relations, fires off for
+ """a special DP that works for many-to-one relationships, fires off for
child items who have changed their referenced key."""
has_dependencies = False
from sqlalchemy.orm.util import _state_has_identity, has_identity
from sqlalchemy.orm import attributes, collections
-class DynaLoader(strategies.AbstractRelationLoader):
+class DynaLoader(strategies.AbstractRelationshipLoader):
def init_class_attribute(self, mapper):
self.is_class_level = True
ColumnProperty = None
SynonymProperty = None
ComparableProperty = None
-RelationProperty = None
+RelationshipProperty = None
ConcreteInheritedProperty = None
_expire_state = None
_state_session = None
def cascade_iterator(self, type_, state, halt_on=None):
"""Iterate each element and its mapper in an object graph,
- for all relations that meet the given cascade rule.
+ for all relationships that meet the given cascade rule.
``type\_``:
The name of the cascade rule (i.e. save-update, delete,
``state``:
The lead InstanceState. child items will be processed per
- the relations defined for this object's mapper.
+ the relationships defined for this object's mapper.
the return value are object instances; this provides a strong
reference so that they don't fall out of scope immediately.
NoneType = type(None)
__all__ = ('ColumnProperty', 'CompositeProperty', 'SynonymProperty',
- 'ComparableProperty', 'RelationProperty', 'BackRef')
+ 'ComparableProperty', 'RelationshipProperty', 'BackRef')
class ColumnProperty(StrategizedProperty):
pass
-class RelationProperty(StrategizedProperty):
+class RelationshipProperty(StrategizedProperty):
"""Describes an object property that holds a single item or list
of items that correspond to a related database table.
"""
self.join_depth = join_depth
self.local_remote_pairs = _local_remote_pairs
self.extension = extension
- self.comparator_factory = comparator_factory or RelationProperty.Comparator
+ self.comparator_factory = comparator_factory or RelationshipProperty.Comparator
self.comparator = self.comparator_factory(self, None)
util.set_creation_order(self)
return op(self, *other, **kwargs)
def of_type(self, cls):
- return RelationProperty.Comparator(self.property, self.mapper, cls, adapter=self.adapter)
+ return RelationshipProperty.Comparator(self.property, self.mapper, cls, adapter=self.adapter)
def in_(self, other):
- raise NotImplementedError("in_() not yet supported for relations. For a "
+ raise NotImplementedError("in_() not yet supported for relationships. For a "
"simple many-to-one, use in_() against the set of foreign key values.")
__hash__ = None
other._reverse_property.add(self)
if not other._get_target().common_parent(self.parent):
- raise sa_exc.ArgumentError("reverse_property %r on relation %s references "
- "relation %s, which does not reference mapper %s" % (key, self, other, self.parent))
+ raise sa_exc.ArgumentError("reverse_property %r on relationship %s references "
+ "relationship %s, which does not reference mapper %s" % (key, self, other, self.parent))
if self.direction in (ONETOMANY, MANYTOONE) and self.direction == other.direction:
raise sa_exc.ArgumentError("%s and back-reference %s are both of the same direction %r."
self._determine_local_remote_pairs()
self._post_init()
self._generate_backref()
- super(RelationProperty, self).do_init()
+ super(RelationshipProperty, self).do_init()
def _get_target(self):
if not hasattr(self, 'mapper'):
# accept a callable to suit various deferred-configurational schemes
self.mapper = mapper.class_mapper(self.argument(), compile=False)
else:
- raise sa_exc.ArgumentError("relation '%s' expects a class or a mapper argument (received: %s)" % (self.key, type(self.argument)))
+ raise sa_exc.ArgumentError("relationship '%s' expects a class or a mapper argument (received: %s)" % (self.key, type(self.argument)))
assert isinstance(self.mapper, mapper.Mapper), self.mapper
return self.mapper
for inheriting in self.parent.iterate_to_root():
if inheriting is not self.parent and inheriting._get_property(self.key, raiseerr=False):
util.warn(
- ("Warning: relation '%s' on mapper '%s' supercedes "
- "the same relation on inherited mapper '%s'; this "
+ ("Warning: relationship '%s' on mapper '%s' supercedes "
+ "the same relationship on inherited mapper '%s'; this "
"can cause dependency issues during flush") %
(self.key, self.parent, inheriting))
self.primaryjoin = _search_for_join(self.parent, self.target)
except sa_exc.ArgumentError, e:
raise sa_exc.ArgumentError("Could not determine join condition between "
- "parent/child tables on relation %s. "
+ "parent/child tables on relationship %s. "
"Specify a 'primaryjoin' expression. If this is a "
- "many-to-many relation, 'secondaryjoin' is needed as well." % (self))
+ "many-to-many relationship, 'secondaryjoin' is needed as well." % (self))
def _col_is_part_of_mappings(self, column):
if self.secondary is None:
if not eq_pairs:
if not self.viewonly and criterion_as_pairs(self.primaryjoin, consider_as_foreign_keys=self._foreign_keys, any_operator=True):
raise sa_exc.ArgumentError("Could not locate any equated, locally "
- "mapped column pairs for primaryjoin condition '%s' on relation %s. "
- "For more relaxed rules on join conditions, the relation may be "
+ "mapped column pairs for primaryjoin condition '%s' on relationship %s. "
+ "For more relaxed rules on join conditions, the relationship may be "
"marked as viewonly=True." % (self.primaryjoin, self)
)
else:
if self._foreign_keys:
- raise sa_exc.ArgumentError("Could not determine relation direction for "
- "primaryjoin condition '%s', on relation %s. "
+ raise sa_exc.ArgumentError("Could not determine relationship direction for "
+ "primaryjoin condition '%s', on relationship %s. "
"Do the columns in 'foreign_keys' represent only the 'foreign' columns "
"in this join condition ?" % (self.primaryjoin, self))
else:
- raise sa_exc.ArgumentError("Could not determine relation direction for "
- "primaryjoin condition '%s', on relation %s. "
+ raise sa_exc.ArgumentError("Could not determine relationship direction for "
+ "primaryjoin condition '%s', on relationship %s. "
"Specify the 'foreign_keys' argument to indicate which columns "
- "on the relation are foreign." % (self.primaryjoin, self))
+ "on the relationship are foreign." % (self.primaryjoin, self))
self.synchronize_pairs = eq_pairs
if not sq_pairs:
if not self.viewonly and criterion_as_pairs(self.secondaryjoin, consider_as_foreign_keys=self._foreign_keys, any_operator=True):
raise sa_exc.ArgumentError("Could not locate any equated, locally mapped "
- "column pairs for secondaryjoin condition '%s' on relation %s. "
+ "column pairs for secondaryjoin condition '%s' on relationship %s. "
"For more relaxed rules on join conditions, the "
- "relation may be marked as viewonly=True." % (self.secondaryjoin, self)
+ "relationship may be marked as viewonly=True." % (self.secondaryjoin, self)
)
else:
- raise sa_exc.ArgumentError("Could not determine relation direction "
- "for secondaryjoin condition '%s', on relation %s. "
+ raise sa_exc.ArgumentError("Could not determine relationship direction "
+ "for secondaryjoin condition '%s', on relationship %s. "
"Specify the foreign_keys argument to indicate which "
- "columns on the relation are foreign." % (self.secondaryjoin, self))
+ "columns on the relationship are foreign." % (self.secondaryjoin, self))
self.secondary_synchronize_pairs = sq_pairs
else:
if not onetomany_fk and not manytoone_fk:
raise sa_exc.ArgumentError(
- "Can't determine relation direction for relationship '%s' "
+ "Can't determine relationship direction for relationship '%s' "
"- foreign key columns are present in neither the "
"parent nor the child's mapped tables" % self )
if not self.direction:
raise sa_exc.ArgumentError(
- "Can't determine relation direction for relationship '%s' "
+ "Can't determine relationship direction for relationship '%s' "
"- foreign key columns are present in both the parent and "
"the child's mapped tables. Specify 'foreign_keys' "
"argument." % self)
(self.direction is MANYTOMANY or self.direction is MANYTOONE):
util.warn("On %s, delete-orphan cascade is not supported on a "
"many-to-many or many-to-one relationship when single_parent is not set. "
- " Set single_parent=True on the relation()." % self)
+ " Set single_parent=True on the relationship()." % self)
def _determine_local_remote_pairs(self):
if not self.local_remote_pairs:
self.local_remote_pairs = criterion_as_pairs(self.primaryjoin, consider_as_foreign_keys=self.remote_side, any_operator=True)
if not self.local_remote_pairs:
- raise sa_exc.ArgumentError("Relation %s could not determine any local/remote column pairs from remote side argument %r" % (self, self.remote_side))
+ raise sa_exc.ArgumentError("Relationship %s could not determine any local/remote column pairs from remote side argument %r" % (self, self.remote_side))
else:
if self.viewonly:
if not self.is_primary() and \
not mapper.class_mapper(self.parent.class_, compile=False)._get_property(self.key, raiseerr=False):
- raise sa_exc.ArgumentError("Attempting to assign a new relation '%s' to "
- "a non-primary mapper on class '%s'. New relations can only be "
+ raise sa_exc.ArgumentError("Attempting to assign a new relationship '%s' to "
+ "a non-primary mapper on class '%s'. New relationships can only be "
"added to the primary mapper, i.e. the very first "
"mapper created for class '%s' " % (self.key, self.parent.class_.__name__, self.parent.class_.__name__))
mapper = self.mapper.primary_mapper()
if mapper._get_property(backref_key, raiseerr=False) is not None:
- raise sa_exc.ArgumentError("Error creating backref '%s' on relation '%s': "
+ raise sa_exc.ArgumentError("Error creating backref '%s' on relationship '%s': "
"property of that name exists on mapper '%s'" % (backref_key, self, mapper))
if self.secondary is not None:
if sj:
raise sa_exc.InvalidRequestError(
"Can't assign 'secondaryjoin' on a backref against "
- "a non-secondary relation.")
+ "a non-secondary relationship.")
foreign_keys = kwargs.pop('foreign_keys', self._foreign_keys)
kwargs.setdefault('post_update', self.post_update)
self.back_populates = backref_key
- relation = RelationProperty(
+ relationship = RelationshipProperty(
parent,
self.secondary,
pj,
back_populates=self.key,
**kwargs)
- mapper._configure_property(backref_key, relation)
+ mapper._configure_property(backref_key, relationship)
if self.back_populates:
self.logger.info("%s synchronize pairs [%s]", self, ",".join("(%s => %s)" % (l, r) for l, r in self.synchronize_pairs))
self.logger.info("%s secondary synchronize pairs [%s]", self, ",".join(("(%s => %s)" % (l, r) for l, r in self.secondary_synchronize_pairs or [])))
self.logger.info("%s local/remote pairs [%s]", self, ",".join("(%s / %s)" % (l, r) for l, r in self.local_remote_pairs))
- self.logger.info("%s relation direction %s", self, self.direction)
+ self.logger.info("%s relationship direction %s", self, self.direction)
if self.uselist is None:
self.uselist = self.direction is not MANYTOONE
if not self.viewonly:
self._dependency_processor.register_processors(uowcommit)
-PropertyLoader = RelationProperty
-log.class_logger(RelationProperty)
+PropertyLoader = RelationshipProperty
+log.class_logger(RelationshipProperty)
mapper.ColumnProperty = ColumnProperty
mapper.SynonymProperty = SynonymProperty
mapper.ComparableProperty = ComparableProperty
-mapper.RelationProperty = RelationProperty
+mapper.RelationshipProperty = RelationshipProperty
mapper.ConcreteInheritedProperty = ConcreteInheritedProperty
Each element in \*props may be:
* a string property name, i.e. "rooms". This will join along the
- relation of the same name from this Query's "primary" mapper, if
+ relationship of the same name from this Query's "primary" mapper, if
one is present.
* a class-mapped attribute, i.e. Houses.rooms. This will create a
- join from "Houses" table to that of the "rooms" relation.
+ join from "Houses" table to that of the "rooms" relationship.
* a 2-tuple containing a target class or selectable, and an "ON"
clause. The ON clause can be the property name/ attribute like
session.query(Company).join('employees', 'tasks')
# join the Person entity to an alias of itself,
- # along the "friends" relation
+ # along the "friends" relationship
PAlias = aliased(Person)
session.query(Person).join((Palias, Person.friends))
# join from Houses to the "rooms" attribute on the
# "Colonials" subclass of Houses, then join to the
- # "closets" relation on Room
+ # "closets" relationship on Room
session.query(Houses).join(Colonials.rooms, Room.closets)
# join from Company entities to the "employees" collection,
session.query(Company).join((people.join(engineers), 'employees'), Engineer.computers)
# join from Articles to Keywords, using the "keywords" attribute.
- # assume this is a many-to-many relation.
+ # assume this is a many-to-many relationship.
session.query(Article).join(Article.keywords)
# same thing, but spelled out entirely explicitly
Returns the number of rows deleted, excluding any cascades.
- The method does *not* offer in-Python cascading of relations - it is
+ The method does *not* offer in-Python cascading of relationships - it is
assumed that ON DELETE CASCADE is configured for any foreign key
references which require it. The Session needs to be expired (occurs
automatically after commit(), or call expire_all()) in order for the
Returns the number of rows matched by the update.
- The method does *not* offer in-Python cascading of relations - it is assumed that
+ The method does *not* offer in-Python cascading of relationships - it is assumed that
ON UPDATE CASCADE is configured for any foreign key references which require it.
The Session needs to be expired (occurs automatically after commit(), or call expire_all())
"""
#TODO: value keys need to be mapped to corresponding sql cols and instr.attr.s to string keys
- #TODO: updates of manytoone relations need to be converted to fk assignments
+ #TODO: updates of manytoone relationships need to be converted to fk assignments
#TODO: cascades need handling.
if synchronize_session == 'expire':
def process_query(self, query):
query._attributes[('undefer', self.group)] = True
-class AbstractRelationLoader(LoaderStrategy):
+class AbstractRelationshipLoader(LoaderStrategy):
"""LoaderStratgies which deal with related objects as opposed to scalars."""
def init(self):
self.table = self.parent_property.table
self.uselist = self.parent_property.uselist
-class NoLoader(AbstractRelationLoader):
- """Strategize a relation() that doesn't load data automatically."""
+class NoLoader(AbstractRelationshipLoader):
+ """Strategize a relationship() that doesn't load data automatically."""
def init_class_attribute(self, mapper):
self.is_class_level = True
log.class_logger(NoLoader)
-class LazyLoader(AbstractRelationLoader):
- """Strategize a relation() that loads when first accessed."""
+class LazyLoader(AbstractRelationshipLoader):
+ """Strategize a relationship() that loads when first accessed."""
def init(self):
super(LazyLoader, self).init()
else:
return None
-class EagerLoader(AbstractRelationLoader):
- """Strategize a relation() that loads within the process of the parent object being selected."""
+class EagerLoader(AbstractRelationshipLoader):
+ """Strategize a relationship() that loads within the process of the parent object being selected."""
def init(self):
super(EagerLoader, self).init()
_state_session = None
class UOWEventHandler(interfaces.AttributeExtension):
- """An event handler added to all relation attributes which handles
+ """An event handler added to all relationship attributes which handles
session cascade operations.
"""
def append_postupdate(self, state, post_update_cols):
"""issue a 'post update' UPDATE statement via this object's mapper immediately.
- this operation is used only with relations that specify the `post_update=True`
+ this operation is used only with relationships that specify the `post_update=True`
flag.
"""
_INSTRUMENTOR = ('mapper', 'instrumentor')
class CascadeOptions(object):
- """Keeps track of the options sent to relation().cascade"""
+ """Keeps track of the options sent to relationship().cascade"""
def __init__(self, arg=""):
if not arg:
In addition to the interface provided by
:func:`~sqlalchemy.sql.expression.join()`, left and right may be mapped
classes or AliasedClass instances. The onclause may be a
- string name of a relation(), or a class-bound descriptor
- representing a relation.
+ string name of a relationship(), or a class-bound descriptor
+ representing a relationship.
join_to_left indicates to attempt aliasing the ON clause,
in whatever form it is passed, to the selectable
In addition to the interface provided by
:func:`~sqlalchemy.sql.expression.outerjoin()`, left and right may be mapped
classes or AliasedClass instances. The onclause may be a
- string name of a relation(), or a class-bound descriptor
- representing a relation.
+ string name of a relationship(), or a class-bound descriptor
+ representing a relationship.
"""
return _ORMJoin(left, right, onclause, True, join_to_left)
from sqlalchemy.test.testing import eq_
-from sqlalchemy.orm import mapper, relation, create_session, clear_mappers, sessionmaker
+from sqlalchemy.orm import mapper, relationship, create_session, clear_mappers, sessionmaker
from sqlalchemy.orm.mapper import _mapper_registry
from sqlalchemy.orm.session import _sessions
from sqlalchemy.util import jython
metadata.create_all()
m1 = mapper(A, table1, properties={
- "bs":relation(B, cascade="all, delete", order_by=table2.c.col1)},
+ "bs":relationship(B, cascade="all, delete", order_by=table2.c.col1)},
order_by=table1.c.col1)
m2 = mapper(B, table2)
@profile_memory
def go():
m1 = mapper(A, table1, properties={
- "bs":relation(B, order_by=table2.c.col1)
+ "bs":relationship(B, order_by=table2.c.col1)
})
m2 = mapper(B, table2)
pass
mapper(A, table1, properties={
- 'bs':relation(B, secondary=table3, backref='as', order_by=table3.c.t1)
+ 'bs':relationship(B, secondary=table3, backref='as', order_by=table3.c.t1)
})
mapper(B, table2)
pass
mapper(Foo, table1, properties={
- 'bars':relation(mapper(Bar, table2))
+ 'bars':relationship(mapper(Bar, table2))
})
metadata.create_all()
from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message
from sqlalchemy import exc as sa_exc, util, Integer, String, ForeignKey
-from sqlalchemy.orm import exc as orm_exc, mapper, relation, sessionmaker
+from sqlalchemy.orm import exc as orm_exc, mapper, relationship, sessionmaker
from sqlalchemy.test import testing, profiling
from test.orm import _base
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(Parent, parent, properties={
- 'children':relation(Child, backref='parent')
+ 'children':relationship(Child, backref='parent')
})
mapper(Child, child)
# want to ensure that
# "null value in column "id" violates not-null constraint" is raised (IntegrityError on psycoopg2,
# but ProgrammingError on pg8000),
- # and not "ProgrammingError: (ProgrammingError) relation "t2_id_seq" does not exist".
+ # and not "ProgrammingError: (ProgrammingError) relationship "t2_id_seq" does not exist".
# the latter corresponds to autoincrement behavior, which is not the case
# here due to the foreign key.
for eng in [
self.name = name
mapper(Parent, parents_table, properties={
- '_children': relation(Child, lazy=False,
+ '_children': relationship(Child, lazy=False,
collection_class=collection_class)})
mapper(Child, children_table)
self.name = name
mapper(Parent, parents_table, properties={
- '_children': relation(Child, lazy=False,
+ '_children': relationship(Child, lazy=False,
collection_class=list)})
mapper(Child, children_table)
setattr(self, attr, kw[attr])
mapper(Parent, parents_table, properties={
- 'child': relation(Child, lazy=False,
+ 'child': relationship(Child, lazy=False,
backref='parent', uselist=False)})
mapper(Child, children_table)
Parent, Child = self.Parent, self.Child
mapper(Parent, self.table, properties={
- '_children': relation(Child, lazy=True,
+ '_children': relationship(Child, lazy=True,
collection_class=list)})
p = Parent('p')
Parent, Child = self.Parent, self.Child
mapper(Parent, self.table, properties={
- '_children': relation(Child, lazy=False,
+ '_children': relationship(Child, lazy=False,
collection_class=list)})
p = Parent('p')
Parent, Child = self.Parent, self.Child
mapper(Parent, self.table, properties={
- '_children': relation(Child, lazy=True, uselist=False)})
+ '_children': relationship(Child, lazy=True, uselist=False)})
p = Parent('p')
Parent, Child = self.Parent, self.Child
mapper(Parent, self.table, properties={
- '_children': relation(Child, lazy=False, uselist=False)})
+ '_children': relationship(Child, lazy=False, uselist=False)})
p = Parent('p')
clear_mappers()
def test_weak_identity_map(self):
- mapper(Parent, self.parents, properties=dict(children=relation(Child)))
+ mapper(Parent, self.parents, properties=dict(children=relationship(Child)))
mapper(Child, self.children)
session = create_session(weak_identity_map=True)
assert set(p.kids) == set(['c1', 'c2']), p.kids
def test_copy(self):
- mapper(Parent, self.parents, properties=dict(children=relation(Child)))
+ mapper(Parent, self.parents, properties=dict(children=relationship(Child)))
mapper(Child, self.children)
p = Parent('p1')
assert set(p_copy.kids) == set(['c1', 'c2']), p.kids
def test_pickle_list(self):
- mapper(Parent, self.parents, properties=dict(children=relation(Child)))
+ mapper(Parent, self.parents, properties=dict(children=relationship(Child)))
mapper(Child, self.children)
p = Parent('p1')
assert r2 == ['c1', 'c2']
def test_pickle_set(self):
- mapper(Parent, self.parents, properties=dict(children=relation(Child, collection_class=set)))
+ mapper(Parent, self.parents, properties=dict(children=relationship(Child, collection_class=set)))
mapper(Child, self.children)
p = Parent('p1')
def test_pickle_dict(self):
mapper(Parent, self.parents, properties=dict(
- children=relation(KVChild, collection_class=collections.mapped_collection(PickleKeyFunc('name')))
+ children=relationship(KVChild, collection_class=collections.mapped_collection(PickleKeyFunc('name')))
))
mapper(KVChild, self.children)
mapper(User, users)
mapper(Keyword, keywords, properties={
- 'user_keyword': relation(UserKeyword, uselist=False)
+ 'user_keyword': relationship(UserKeyword, uselist=False)
})
mapper(UserKeyword, userkeywords, properties={
- 'user': relation(User, backref='user_keywords'),
- 'keyword': relation(Keyword),
+ 'user': relationship(User, backref='user_keywords'),
+ 'keyword': relationship(Keyword),
})
@classmethod
from sqlalchemy.test import testing
from sqlalchemy import MetaData, Integer, String, ForeignKey, ForeignKeyConstraint, asc, Index
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import relation, create_session, class_mapper, eagerload, compile_mappers, backref, clear_mappers, polymorphic_union, deferred
+from sqlalchemy.orm import relationship, create_session, class_mapper, eagerload, compile_mappers, backref, clear_mappers, polymorphic_union, deferred
from sqlalchemy.test.testing import eq_
from sqlalchemy.util import classproperty
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- addresses = relation("Address", backref="user")
+ addresses = relationship("Address", backref="user")
class Address(Base, ComparableEntity):
__tablename__ = 'addresses'
id = Column('id', Integer, primary_key=True)
email = Column('email', String(50))
user_id = Column('user_id', Integer, ForeignKey('users.id'))
- user = relation("User", primaryjoin=user_id == User.id,
+ user = relationship("User", primaryjoin=user_id == User.id,
backref="addresses")
assert mapperlib._new_mappers is True
__tablename__ = 'users'
id = Column(Integer, primary_key=True, test_needs_autoincrement=True)
name = Column(String(50))
- addresses = relation("Address", order_by="desc(Address.email)",
+ addresses = relationship("Address", order_by="desc(Address.email)",
primaryjoin="User.id==Address.user_id", foreign_keys="[Address.user_id]",
backref=backref('user', primaryjoin="User.id==Address.user_id", foreign_keys="[Address.user_id]")
)
class Foo(Base, ComparableEntity):
__tablename__ = 'foo'
id = Column(Integer, primary_key=True)
- rel = relation("User", primaryjoin="User.addresses==Foo.id")
+ rel = relationship("User", primaryjoin="User.addresses==Foo.id")
assert_raises_message(exc.InvalidRequestError, "'addresses' is not an instance of ColumnProperty", compile_mappers)
def test_string_dependency_resolution_no_magic(self):
class User(Base, ComparableEntity):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
- addresses = relation("Address",
+ addresses = relationship("Address",
primaryjoin="User.id==Address.user_id.prop.columns[0]")
class Address(Base, ComparableEntity):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String(50))
- addresses = relation("Address",
+ addresses = relationship("Address",
primaryjoin="User.id==Address.user_id",
backref="user"
)
id = Column(Integer, primary_key=True)
name = Column(String(50))
- props = relation("Prop",
+ props = relationship("Prop",
secondary="user_to_prop",
primaryjoin="User.id==user_to_prop.c.user_id",
secondaryjoin="user_to_prop.c.prop_id==Prop.id",
compile_mappers()
assert class_mapper(User).get_property("props").secondary is user_to_prop
- def test_uncompiled_attributes_in_relation(self):
+ def test_uncompiled_attributes_in_relationship(self):
class Address(Base, ComparableEntity):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True, test_needs_autoincrement=True)
__tablename__ = 'users'
id = Column(Integer, primary_key=True, test_needs_autoincrement=True)
name = Column(String(50))
- addresses = relation("Address", order_by=Address.email,
+ addresses = relationship("Address", order_by=Address.email,
foreign_keys=Address.user_id,
remote_side=Address.user_id,
)
# get the mapper for User. User mapper will compile,
- # "addresses" relation will call upon Address.user_id for
+ # "addresses" relationship will call upon Address.user_id for
# its clause element. Address.user_id is a _CompileOnAttr,
# which then calls class_mapper(Address). But ! We're already
# "in compilation", but class_mapper(Address) needs to initialize
class User(Base):
__tablename__ = 'users'
id = Column('id', Integer, primary_key=True)
- addresses = relation("Address")
+ addresses = relationship("Address")
class Address(Base):
__tablename__ = 'addresses'
class User(Base):
__tablename__ = 'users'
id = Column('id', Integer, primary_key=True)
- addresses = relation("Addresss")
+ addresses = relationship("Addresss")
# hasattr() on a compile-loaded attribute
hasattr(User.addresses, 'property')
__tablename__ = 'detail'
id = Column(Integer, primary_key=True, test_needs_autoincrement=True)
master_id = Column(None, ForeignKey(Master.id))
- master = relation(Master)
+ master = relationship(Master)
Base.metadata.create_all()
__tablename__ = 'users'
id = Column('id', Integer, primary_key=True)
name = Column('name', String(50))
- error = relation("Address")
+ error = relationship("Address")
i = Index('my_index', User.name)
- # compile fails due to the nonexistent Addresses relation
+ # compile fails due to the nonexistent Addresses relationship
assert_raises(sa.exc.InvalidRequestError, compile_mappers)
# index configured
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
User.name = Column('name', String(50))
- User.addresses = relation("Address", backref="user")
+ User.addresses = relationship("Address", backref="user")
class Address(Base, ComparableEntity):
__tablename__ = 'addresses'
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- addresses = relation("Address", order_by=Address.email)
+ addresses = relationship("Address", order_by=Address.email)
Base.metadata.create_all()
u1 = User(name='u1', addresses=[
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- addresses = relation("Address", order_by=(Address.email, Address.id))
+ addresses = relationship("Address", order_by=(Address.email, Address.id))
Base.metadata.create_all()
u1 = User(name='u1', addresses=[
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- addresses = relation("Address", backref="user")
+ addresses = relationship("Address", backref="user")
class Address(ComparableEntity):
__tablename__ = 'addresses'
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- addresses = relation("Address", backref="user")
+ addresses = relationship("Address", backref="user")
class Address(Base, ComparableEntity):
__tablename__ = 'addresses'
adr_count = sa.orm.column_property(
sa.select([sa.func.count(Address.id)], Address.user_id == id).
as_scalar())
- addresses = relation(Address)
+ addresses = relationship(Address)
Base.metadata.create_all()
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- addresses = relation("Address", backref="user")
+ addresses = relationship("Address", backref="user")
class Address(Base, ComparableEntity):
__tablename__ = 'addresses'
Address(email='two'),
])])
- def test_relation_reference(self):
+ def test_relationship_reference(self):
class Address(Base, ComparableEntity):
__tablename__ = 'addresses'
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- addresses = relation("Address", backref="user",
+ addresses = relationship("Address", backref="user",
primaryjoin=id == Address.user_id)
User.address_count = sa.orm.column_property(
__tablename__ = 'foo'
id = sa.Column(sa.Integer, primary_key=True)
- bars = sa.orm.relation(Bar)
+ bars = sa.orm.relationship(Bar)
assert Bar.__mapper__.primary_key[0] is Bar.__table__.c.id
assert Bar.__mapper__.primary_key[1] is Bar.__table__.c.ex
__tablename__ = 'companies'
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- employees = relation("Person")
+ employees = relationship("Person")
class Person(Base, ComparableEntity):
__tablename__ = 'people'
__tablename__ = 'companies'
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- employees = relation("Person")
+ employees = relationship("Person")
class Person(Base, ComparableEntity):
__tablename__ = 'people'
__tablename__ = 'companies'
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- employees = relation("Person")
+ employees = relationship("Person")
class Person(Base, ComparableEntity):
__tablename__ = 'people'
__tablename__ = 'companies'
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
name = Column('name', String(50))
- employees = relation("Person")
+ employees = relationship("Person")
class Person(Base, ComparableEntity):
__tablename__ = 'people'
class Engineer(Person):
__mapper_args__ = {'polymorphic_identity':'engineer'}
primary_language_id = Column(Integer, ForeignKey('languages.id'))
- primary_language = relation("Language")
+ primary_language = relationship("Language")
class Language(Base, ComparableEntity):
__tablename__ = 'languages'
user_id = Column(Integer, ForeignKey('users.id'))
if inline:
if stringbased:
- user = relation("User", primaryjoin="User.id==Address.user_id", backref="addresses")
+ user = relationship("User", primaryjoin="User.id==Address.user_id", backref="addresses")
else:
- user = relation(User, primaryjoin=User.id==user_id, backref="addresses")
+ user = relationship(User, primaryjoin=User.id==user_id, backref="addresses")
if not inline:
compile_mappers()
if stringbased:
- Address.user = relation("User", primaryjoin="User.id==Address.user_id", backref="addresses")
+ Address.user = relationship("User", primaryjoin="User.id==Address.user_id", backref="addresses")
else:
- Address.user = relation(User, primaryjoin=User.id==Address.user_id, backref="addresses")
+ Address.user = relationship(User, primaryjoin=User.id==Address.user_id, backref="addresses")
@classmethod
def insert_data(cls):
def test_aliased_join(self):
# this query will screw up if the aliasing
# enabled in query.join() gets applied to the right half of the join condition inside the any().
- # the join condition inside of any() comes from the "primaryjoin" of the relation,
+ # the join condition inside of any() comes from the "primaryjoin" of the relationship,
# and should not be annotated with _orm_adapt. PropertyLoader.Comparator will annotate
# the left side with _orm_adapt, though.
sess = create_session()
__autoload__ = True
if testing.against('oracle', 'firebird'):
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
- addresses = relation("Address", backref="user")
+ addresses = relationship("Address", backref="user")
class Address(Base, ComparableEntity):
__tablename__ = 'addresses'
if testing.against('oracle', 'firebird'):
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
nom = Column('name', String(50), key='nom')
- addresses = relation("Address", backref="user")
+ addresses = relationship("Address", backref="user")
class Address(Base, ComparableEntity):
__tablename__ = 'addresses'
__autoload__ = True
if testing.against('oracle', 'firebird'):
id = Column('id', Integer, primary_key=True, test_needs_autoincrement=True)
- handles = relation("IMHandle", backref="user")
+ handles = relationship("IMHandle", backref="user")
u1 = User(name='u1', handles=[
IMHandle(network='blabber', handle='foo'),
metadata.clear()
def _setup(self, test_collection_class):
- """Build a relation situation using the given test_collection_class
+ """Build a relationship situation using the given test_collection_class
factory"""
global metadata, slides_table, bullets_table, Slide, Bullet
return '<Bullet "%s" pos %s>' % (self.text, self.position)
mapper(Slide, slides_table, properties={
- 'bullets': relation(Bullet, lazy=False,
+ 'bullets': relationship(Bullet, lazy=False,
collection_class=test_collection_class,
backref='slide',
order_by=[bullets_table.c.position])
from sqlalchemy import MetaData, Integer, String, ForeignKey, select, desc, func, util
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import relation, sessionmaker, scoped_session, class_mapper, mapper, eagerload, compile_mappers, aliased
+from sqlalchemy.orm import relationship, sessionmaker, scoped_session, class_mapper, mapper, eagerload, compile_mappers, aliased
from sqlalchemy.test.testing import eq_
from test.orm._base import ComparableEntity, MappedTest
Session = scoped_session(sessionmaker())
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', order_by=addresses.c.id)
+ 'addresses':relationship(Address, backref='user', order_by=addresses.c.id)
})
mapper(Address, addresses)
btoc = tc.c.id==tb.c.id
if direction == ONETOMANY:
- relationjoin = parent_table.c.id==child_table.c.parent_id
+ relationshipjoin = parent_table.c.id==child_table.c.parent_id
elif direction == MANYTOONE:
- relationjoin = parent_table.c.child_id==child_table.c.id
+ relationshipjoin = parent_table.c.child_id==child_table.c.id
if parent is child:
remote_side = [child_table.c.id]
parent_class = parent_mapper.class_
child_class = child_mapper.class_
- parent_mapper.add_property("collection", relation(child_mapper, primaryjoin=relationjoin, foreign_keys=foreign_keys, remote_side=remote_side, uselist=True))
+ parent_mapper.add_property("collection", relationship(child_mapper, primaryjoin=relationshipjoin, foreign_keys=foreign_keys, remote_side=remote_side, uselist=True))
sess = create_session()
return "Blub id %d, data %s" % (self.id, self.data)
mapper(Blub, blub, inherits=Bar, properties={
- 'parent_foo':relation(Foo)
+ 'parent_foo':relationship(Foo)
})
sess = create_session()
class CascadeTest(_base.MappedTest):
- """that cascades on polymorphic relations continue
+ """that cascades on polymorphic relationships continue
cascading along the path of the instance's mapper, not
the base mapper."""
pass
mapper(T1, t1, properties={
- 't2s':relation(T2, cascade="all")
+ 't2s':relationship(T2, cascade="all")
})
mapper(T2, t2, polymorphic_on=t2.c.type, polymorphic_identity='t2')
mapper(T3, t3, inherits=T2, polymorphic_identity='t3', properties={
- 't4s':relation(T4, cascade="all")
+ 't4s':relationship(T4, cascade="all")
})
mapper(T4, t4)
# previously, this was needed for the comparison to occur:
# the 'primaryjoin' looks just like "Sub"'s "get" clause (based on the Base id),
# and foreign_keys since that join condition doesn't actually have any fks in it
- #'sub':relation(Sub, primaryjoin=base.c.id==related.c.sub_id, foreign_keys=related.c.sub_id)
+ #'sub':relationship(Sub, primaryjoin=base.c.id==related.c.sub_id, foreign_keys=related.c.sub_id)
# now we can use this:
- 'sub':relation(Sub)
+ 'sub':relationship(Sub)
})
assert class_mapper(Related).get_property('sub').strategy.use_get
foos = mapper(Foo, foo)
bars = mapper(Bar, bar, inherits=foos)
- bars.add_property('lazy', relation(foos, bar_foo, lazy=True))
- bars.add_property('eager', relation(foos, bar_foo, lazy=False))
+ bars.add_property('lazy', relationship(foos, bar_foo, lazy=True))
+ bars.add_property('eager', relationship(foos, bar_foo, lazy=False))
foo.insert().execute(data='foo1')
bar.insert().execute(id=1, data='bar1')
mapper(A, a_table, polymorphic_on=a_table.c.type, polymorphic_identity='A',
properties={
- 'children': relation(A, order_by=a_table.c.name)
+ 'children': relationship(A, order_by=a_table.c.name)
})
mapper(B, b_table, inherits=A, polymorphic_identity='B', properties={
class Admin(User):pass
role_mapper = mapper(Role, roles)
user_mapper = mapper(User, users, properties = {
- 'roles' : relation(Role, secondary=user_roles, lazy=False)
+ 'roles' : relationship(Role, secondary=user_roles, lazy=False)
}
)
admin_mapper = mapper(Admin, admins, inherits=user_mapper)
role_mapper = mapper(Role, roles)
user_mapper = mapper(User, users, properties = {
- 'roles' : relation(Role, secondary=user_roles, lazy=False)
+ 'roles' : relationship(Role, secondary=user_roles, lazy=False)
}
)
polymorphic_on=base.c.discriminator,
version_id_col=base.c.version_id,
polymorphic_identity=1, properties={
- 'stuff':relation(Stuff)
+ 'stuff':relationship(Stuff)
})
mapper(Sub, subtable, inherits=Base, polymorphic_identity=2)
pass
mapper(Parent, parents, properties={
- 'children': relation(Child, backref='parent'),
+ 'children': relationship(Child, backref='parent'),
})
mapper(Child, children, polymorphic_on=children.c.type,
polymorphic_identity=1)
mapper(Base, single, polymorphic_on=single.c.type, polymorphic_identity='base')
mapper(SubClass, inherits=Base, polymorphic_identity='sub')
mapper(Parent, parent, properties={
- 'related':relation(Base, cascade="all, delete-orphan")
+ 'related':relationship(Base, cascade="all, delete-orphan")
})
sess = create_session()
set(["Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack"])
)
- def test_relation(self):
+ def test_relationship(self):
pjoin = polymorphic_union({
'manager':managers_table,
'engineer':engineers_table
}, 'type', 'pjoin')
mapper(Company, companies, properties={
- 'employees':relation(Employee)
+ 'employees':relationship(Employee)
})
employee_mapper = mapper(Employee, pjoin, polymorphic_on=pjoin.c.type)
manager_mapper = mapper(Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity='manager')
@testing.resolve_artifact_names
def test_noninherited_warning(self):
mapper(A, a_table, properties={
- 'some_c':relation(C)
+ 'some_c':relationship(C)
})
mapper(B, b_table,inherits=A, concrete=True)
mapper(C, c_table)
@testing.resolve_artifact_names
def test_inheriting(self):
mapper(A, a_table, properties={
- 'some_c':relation(C, back_populates='many_a')
+ 'some_c':relationship(C, back_populates='many_a')
})
mapper(B, b_table,inherits=A, concrete=True, properties={
- 'some_c':relation(C, back_populates='many_b')
+ 'some_c':relationship(C, back_populates='many_b')
})
mapper(C, c_table, properties={
- 'many_a':relation(A, back_populates='some_c'),
- 'many_b':relation(B, back_populates='some_c'),
+ 'many_a':relationship(A, back_populates='some_c'),
+ 'many_b':relationship(B, back_populates='some_c'),
})
sess = sessionmaker()()
mapper(A, a_table, with_polymorphic=('*', ajoin),
polymorphic_on=ajoin.c.type, polymorphic_identity='a',
properties={
- 'some_c':relation(C, back_populates='many_a')
+ 'some_c':relationship(C, back_populates='many_a')
})
mapper(B, b_table,inherits=A, concrete=True,
polymorphic_identity='b',
properties={
- 'some_c':relation(C, back_populates='many_a')
+ 'some_c':relationship(C, back_populates='many_a')
})
mapper(C, c_table, properties={
- 'many_a':relation(A, back_populates='some_c', order_by=ajoin.c.id),
+ 'many_a':relationship(A, back_populates='some_c', order_by=ajoin.c.id),
})
sess = sessionmaker()()
pass
@testing.resolve_artifact_names
- def test_selective_relations(self):
+ def test_selective_relationships(self):
mapper(Base, base, properties={
- 'related':relation(Related, secondary=base_mtom, backref='bases', order_by=related.c.id)
+ 'related':relationship(Related, secondary=base_mtom, backref='bases', order_by=related.c.id)
})
mapper(Sub, sub, inherits=Base, concrete=True, properties={
- 'related':relation(Related, secondary=sub_mtom, backref='subs', order_by=related.c.id)
+ 'related':relationship(Related, secondary=sub_mtom, backref='subs', order_by=related.c.id)
})
mapper(Related, related)
publication_mapper = mapper(Publication, publication_table)
issue_mapper = mapper(Issue, issue_table, properties = {
- 'publication': relation(Publication, backref=backref('issues', cascade="all, delete-orphan")),
+ 'publication': relationship(Publication, backref=backref('issues', cascade="all, delete-orphan")),
})
location_name_mapper = mapper(LocationName, location_name_table)
location_mapper = mapper(Location, location_table, properties = {
- 'issue': relation(Issue, backref=backref('locations', lazy=False, cascade="all, delete-orphan")),
- '_name': relation(LocationName),
+ 'issue': relationship(Issue, backref=backref('locations', lazy=False, cascade="all, delete-orphan")),
+ '_name': relationship(LocationName),
})
page_size_mapper = mapper(PageSize, page_size_table)
magazine_mapper = mapper(Magazine, magazine_table, properties = {
- 'location': relation(Location, backref=backref('magazine', uselist=False)),
- 'size': relation(PageSize),
+ 'location': relationship(Location, backref=backref('magazine', uselist=False)),
+ 'size': relationship(PageSize),
})
if use_unions:
'c': page_table.join(magazine_page_table).join(classified_page_table),
}, None, 'page_join')
magazine_page_mapper = mapper(MagazinePage, magazine_page_table, with_polymorphic=('*', magazine_join), inherits=page_mapper, polymorphic_identity='m', properties={
- 'magazine': relation(Magazine, backref=backref('pages', order_by=magazine_join.c.page_no))
+ 'magazine': relationship(Magazine, backref=backref('pages', order_by=magazine_join.c.page_no))
})
elif use_joins:
magazine_join = page_table.join(magazine_page_table).outerjoin(classified_page_table)
magazine_page_mapper = mapper(MagazinePage, magazine_page_table, with_polymorphic=('*', magazine_join), inherits=page_mapper, polymorphic_identity='m', properties={
- 'magazine': relation(Magazine, backref=backref('pages', order_by=page_table.c.page_no))
+ 'magazine': relationship(Magazine, backref=backref('pages', order_by=page_table.c.page_no))
})
else:
magazine_page_mapper = mapper(MagazinePage, magazine_page_table, inherits=page_mapper, polymorphic_identity='m', properties={
- 'magazine': relation(Magazine, backref=backref('pages', order_by=page_table.c.page_no))
+ 'magazine': relationship(Magazine, backref=backref('pages', order_by=page_table.c.page_no))
})
classified_page_mapper = mapper(ClassifiedPage,
mapper(User, users, inherits=Principal)
mapper(Group, groups, inherits=Principal, properties={
- 'users': relation(User, secondary=user_group_map,
+ 'users': relationship(User, secondary=user_group_map,
lazy=True, backref="groups")
})
pass
mapper(Bar, bar, inherits=Foo, properties={
- 'foos': relation(Foo, secondary=foo_bar, lazy=False)
+ 'foos': relationship(Foo, secondary=foo_bar, lazy=False)
})
sess = create_session()
return "Bar id %d, data %s" % (self.id, self.data)
mapper(Bar, bar, inherits=Foo, properties={
- 'foos' :relation(Foo, secondary=bar_foo, lazy=True)
+ 'foos' :relationship(Foo, secondary=bar_foo, lazy=True)
})
sess = create_session()
return "Blub id %d, data %s, bars %s, foos %s" % (self.id, self.data, repr([b for b in self.bars]), repr([f for f in self.foos]))
mapper(Blub, blub, inherits=Bar, properties={
- 'bars':relation(Bar, secondary=blub_bar, lazy=False),
- 'foos':relation(Foo, secondary=blub_foo, lazy=False),
+ 'bars':relationship(Bar, secondary=blub_bar, lazy=False),
+ 'foos':relationship(Foo, secondary=blub_foo, lazy=False),
})
sess = create_session()
polymorphic_on=table1.c.type,
polymorphic_identity='table1',
properties={
- 'nxt': relation(Table1,
+ 'nxt': relationship(Table1,
backref=backref('prev', foreignkey=join.c.id, uselist=False),
uselist=False, primaryjoin=join.c.id==join.c.related_id),
- 'data':relation(mapper(Data, data))
+ 'data':relationship(mapper(Data, data))
},
order_by=table1.c.id)
table1_mapper.compile()
# currently, the "eager" relationships degrade to lazy relationships
# due to the polymorphic load.
- # the "nxt" relation used to have a "lazy=False" on it, but the EagerLoader raises the "self-referential"
- # exception now. since eager loading would never work for that relation anyway, its better that the user
+ # the "nxt" relationship used to have a "lazy=False" on it, but the EagerLoader raises the "self-referential"
+ # exception now. since eager loading would never work for that relationship anyway, its better that the user
# gets an exception instead of it silently not eager loading.
# NOTE: using "nxt" instead of "next" to avoid 2to3 turning it into __next__() for some reason.
table1_mapper = mapper(Table1, table1,
polymorphic_on=table1.c.type,
polymorphic_identity='table1',
properties={
- 'nxt': relation(Table1,
+ 'nxt': relationship(Table1,
backref=backref('prev', remote_side=table1.c.id, uselist=False),
uselist=False, primaryjoin=table1.c.id==table1.c.related_id),
- 'data':relation(mapper(Data, data), lazy=False, order_by=data.c.id)
+ 'data':relationship(mapper(Data, data), lazy=False, order_by=data.c.id)
},
order_by=table1.c.id
)
-"""tests basic polymorphic mapper loading/saving, minimal relations"""
+"""tests basic polymorphic mapper loading/saving, minimal relationships"""
from sqlalchemy.test.testing import eq_, assert_raises, assert_raises_message
from sqlalchemy import *
mapper(Engineer, engineers, inherits=person_mapper, polymorphic_identity='engineer')
mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager')
mapper(Company, companies, properties={
- 'employees': relation(Person,
+ 'employees': relationship(Person,
backref='company',
order_by=person_join.c.person_id)
})
session.expunge_all()
eq_(session.query(Company).get(c.company_id), c)
-class RelationToSubclassTest(PolymorphTest):
+class RelationshipToSubclassTest(PolymorphTest):
def test_basic(self):
- """test a relation to an inheriting mapper where the relation is to a subclass
+ """test a relationship to an inheriting mapper where the relationship is to a subclass
but the join condition is expressed by the parent table.
also test that backrefs work in this case.
this test touches upon a lot of the join/foreign key determination code in properties.py
and creates the need for properties.py to search for conditions individually within
- the mapper's local table as well as the mapper's 'mapped' table, so that relations
- requiring lots of specificity (like self-referential joins) as well as relations requiring
+ the mapper's local table as well as the mapper's 'mapped' table, so that relationships
+ requiring lots of specificity (like self-referential joins) as well as relationships requiring
more generalization (like the example here) both come up with proper results."""
mapper(Person, people)
mapper(Manager, managers, inherits=Person)
mapper(Company, companies, properties={
- 'managers': relation(Manager, backref="company")
+ 'managers': relationship(Manager, backref="company")
})
sess = create_session()
class RoundTripTest(PolymorphTest):
pass
-def _generate_round_trip_test(include_base, lazy_relation, redefine_colprop, with_polymorphic):
+def _generate_round_trip_test(include_base, lazy_relationship, redefine_colprop, with_polymorphic):
"""generates a round trip test.
include_base - whether or not to include the base 'person' type in the union.
- lazy_relation - whether or not the Company relation to People is lazy or eager.
+ lazy_relationship - whether or not the Company relationship to People is lazy or eager.
redefine_colprop - if we redefine the 'name' column to be 'people_name' on the base Person class
use_literal_join - primary join condition is explicitly specified
"""
mapper(Boss, boss, inherits=Manager, polymorphic_identity='boss')
mapper(Company, companies, properties={
- 'employees': relation(Person, lazy=lazy_relation,
+ 'employees': relationship(Person, lazy=lazy_relationship,
cascade="all, delete-orphan",
backref="company", order_by=people.c.person_id
)
cc = session.query(Company).get(c.company_id)
eq_(cc.employees, employees)
- if not lazy_relation:
+ if not lazy_relationship:
if with_polymorphic != 'none':
self.assert_sql_count(testing.db, go, 1)
else:
test_roundtrip = function_named(
test_roundtrip, "test_%s%s%s_%s" % (
- (lazy_relation and "lazy" or "eager"),
+ (lazy_relationship and "lazy" or "eager"),
(include_base and "_inclbase" or ""),
(redefine_colprop and "_redefcol" or ""),
with_polymorphic))
setattr(RoundTripTest, test_roundtrip.__name__, test_roundtrip)
-for lazy_relation in [True, False]:
+for lazy_relationship in [True, False]:
for redefine_colprop in [True, False]:
for with_polymorphic in ['unions', 'joins', 'auto', 'none']:
if with_polymorphic == 'unions':
for include_base in [True, False]:
- _generate_round_trip_test(include_base, lazy_relation, redefine_colprop, with_polymorphic)
+ _generate_round_trip_test(include_base, lazy_relationship, redefine_colprop, with_polymorphic)
else:
- _generate_round_trip_test(False, lazy_relation, redefine_colprop, with_polymorphic)
+ _generate_round_trip_test(False, lazy_relationship, redefine_colprop, with_polymorphic)
return self.__class__.__name__ + "(%s)" % (hex(id(self)))
-class RelationTest1(_base.MappedTest):
+class RelationshipTest1(_base.MappedTest):
"""test self-referential relationships on polymorphic mappers"""
@classmethod
def define_tables(cls, metadata):
def teardown(self):
people.update(values={people.c.manager_id:None}).execute()
- super(RelationTest1, self).teardown()
+ super(RelationshipTest1, self).teardown()
def test_parent_refs_descendant(self):
class Person(AttrSettable):
# note that up until recently (0.4.4), we had to specify "foreign_keys" here
# for this primary join.
mapper(Person, people, properties={
- 'manager':relation(Manager, primaryjoin=(people.c.manager_id ==
+ 'manager':relationship(Manager, primaryjoin=(people.c.manager_id ==
managers.c.person_id),
uselist=False, post_update=True)
})
mapper(Person, people)
mapper(Manager, managers, inherits=Person, inherit_condition=people.c.person_id==managers.c.person_id, properties={
- 'employee':relation(Person, primaryjoin=(people.c.manager_id ==
+ 'employee':relationship(Person, primaryjoin=(people.c.manager_id ==
managers.c.person_id),
foreign_keys=[people.c.manager_id],
uselist=False, post_update=True)
print p, m, m.employee
assert m.employee is p
-class RelationTest2(_base.MappedTest):
+class RelationshipTest2(_base.MappedTest):
"""test self-referential relationships on polymorphic mappers"""
@classmethod
def define_tables(cls, metadata):
Column('data', String(30))
)
- def testrelationonsubclass_j1_nodata(self):
+ def testrelationshiponsubclass_j1_nodata(self):
self.do_test("join1", False)
- def testrelationonsubclass_j2_nodata(self):
+ def testrelationshiponsubclass_j2_nodata(self):
self.do_test("join2", False)
- def testrelationonsubclass_j1_data(self):
+ def testrelationshiponsubclass_j1_data(self):
self.do_test("join1", True)
- def testrelationonsubclass_j2_data(self):
+ def testrelationshiponsubclass_j2_data(self):
self.do_test("join2", True)
- def testrelationonsubclass_j3_nodata(self):
+ def testrelationshiponsubclass_j3_nodata(self):
self.do_test("join3", False)
- def testrelationonsubclass_j3_data(self):
+ def testrelationshiponsubclass_j3_data(self):
self.do_test("join3", True)
def do_test(self, jointype="join1", usedata=False):
if usedata:
mapper(Manager, managers, inherits=Person, inherit_condition=people.c.person_id==managers.c.person_id, polymorphic_identity='manager',
properties={
- 'colleague':relation(Person, primaryjoin=managers.c.manager_id==people.c.person_id, lazy=True, uselist=False),
- 'data':relation(Data, uselist=False)
+ 'colleague':relationship(Person, primaryjoin=managers.c.manager_id==people.c.person_id, lazy=True, uselist=False),
+ 'data':relationship(Data, uselist=False)
}
)
else:
mapper(Manager, managers, inherits=Person, inherit_condition=people.c.person_id==managers.c.person_id, polymorphic_identity='manager',
properties={
- 'colleague':relation(Person, primaryjoin=managers.c.manager_id==people.c.person_id, lazy=True, uselist=False)
+ 'colleague':relationship(Person, primaryjoin=managers.c.manager_id==people.c.person_id, lazy=True, uselist=False)
}
)
if usedata:
assert m.data.data == 'ms data'
-class RelationTest3(_base.MappedTest):
+class RelationshipTest3(_base.MappedTest):
"""test self-referential relationships on polymorphic mappers"""
@classmethod
def define_tables(cls, metadata):
if usedata:
mapper(Person, people, with_polymorphic=('*', poly_union), polymorphic_identity='person', polymorphic_on=people.c.type,
properties={
- 'colleagues':relation(Person, primaryjoin=people.c.colleague_id==people.c.person_id, remote_side=people.c.colleague_id, uselist=True),
- 'data':relation(Data, uselist=False)
+ 'colleagues':relationship(Person, primaryjoin=people.c.colleague_id==people.c.person_id, remote_side=people.c.colleague_id, uselist=True),
+ 'data':relationship(Data, uselist=False)
}
)
else:
mapper(Person, people, with_polymorphic=('*', poly_union), polymorphic_identity='person', polymorphic_on=people.c.type,
properties={
- 'colleagues':relation(Person, primaryjoin=people.c.colleague_id==people.c.person_id,
+ 'colleagues':relationship(Person, primaryjoin=people.c.colleague_id==people.c.person_id,
remote_side=people.c.colleague_id, uselist=True)
}
)
assert m.data.data == 'ms data'
do_test = function_named(
- do_test, 'test_relation_on_base_class_%s_%s' % (
+ do_test, 'test_relationship_on_base_class_%s_%s' % (
jointype, data and "nodata" or "data"))
return do_test
for jointype in ["join1", "join2", "join3", "join4"]:
for data in (True, False):
func = _generate_test(jointype, data)
- setattr(RelationTest3, func.__name__, func)
+ setattr(RelationshipTest3, func.__name__, func)
del func
-class RelationTest4(_base.MappedTest):
+class RelationshipTest4(_base.MappedTest):
@classmethod
def define_tables(cls, metadata):
global people, engineers, managers, cars
person_mapper = mapper(Person, people, with_polymorphic=('*', employee_join), polymorphic_on=employee_join.c.type, polymorphic_identity='person')
engineer_mapper = mapper(Engineer, engineers, inherits=person_mapper, polymorphic_identity='engineer')
manager_mapper = mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager')
- car_mapper = mapper(Car, cars, properties= {'employee':relation(person_mapper)})
+ car_mapper = mapper(Car, cars, properties= {'employee':relationship(person_mapper)})
session = create_session()
c = s.join("employee").filter(Person.name=="E4")[0]
assert c.car_id==car1.car_id
-class RelationTest5(_base.MappedTest):
+class RelationshipTest5(_base.MappedTest):
@classmethod
def define_tables(cls, metadata):
global people, engineers, managers, cars
Column('owner', Integer, ForeignKey('people.person_id')))
def test_eager_empty(self):
- """test parent object with child relation to an inheriting mapper, using eager loads,
+ """test parent object with child relationship to an inheriting mapper, using eager loads,
works when there are no child objects present"""
class Person(object):
def __init__(self, **kwargs):
person_mapper = mapper(Person, people, polymorphic_on=people.c.type, polymorphic_identity='person')
engineer_mapper = mapper(Engineer, engineers, inherits=person_mapper, polymorphic_identity='engineer')
manager_mapper = mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager')
- car_mapper = mapper(Car, cars, properties= {'manager':relation(manager_mapper, lazy=False)})
+ car_mapper = mapper(Car, cars, properties= {'manager':relationship(manager_mapper, lazy=False)})
sess = create_session()
car1 = Car()
assert carlist[0].manager is None
assert carlist[1].manager.person_id == car2.manager.person_id
-class RelationTest6(_base.MappedTest):
+class RelationshipTest6(_base.MappedTest):
"""test self-referential relationships on a single joined-table inheritance mapper"""
@classmethod
def define_tables(cls, metadata):
# to parent.mapped_table
mapper(Manager, managers, inherits=Person, inherit_condition=people.c.person_id==managers.c.person_id,
properties={
- 'colleague':relation(Manager, primaryjoin=managers.c.colleague_id==managers.c.person_id, lazy=True, uselist=False)
+ 'colleague':relationship(Manager, primaryjoin=managers.c.colleague_id==managers.c.person_id, lazy=True, uselist=False)
}
)
m2 = sess.query(Manager).get(m2.person_id)
assert m.colleague is m2
-class RelationTest7(_base.MappedTest):
+class RelationshipTest7(_base.MappedTest):
@classmethod
def define_tables(cls, metadata):
global people, engineers, managers, cars, offroad_cars
with_polymorphic=('*', employee_join), polymorphic_on=employee_join.c.type,
polymorphic_identity='person',
properties={
- 'car':relation(car_mapper)
+ 'car':relationship(car_mapper)
})
engineer_mapper = mapper(Engineer, engineers, inherits=person_mapper, polymorphic_identity='engineer')
manager_mapper = mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager')
for p in r:
assert p.car_id == p.car.car_id
-class RelationTest8(_base.MappedTest):
+class RelationshipTest8(_base.MappedTest):
@classmethod
def define_tables(cls, metadata):
global taggable, users
pass
mapper( Taggable, taggable, polymorphic_on=taggable.c.type, polymorphic_identity='taggable', properties = {
- 'owner' : relation (User,
+ 'owner' : relationship (User,
primaryjoin=taggable.c.owner_id ==taggable.c.id,
remote_side=taggable.c.id
),
status_mapper = mapper(Status, status)
person_mapper = mapper(Person, people,
with_polymorphic=('*', employee_join), polymorphic_on=employee_join.c.type,
- polymorphic_identity='person', properties={'status':relation(status_mapper)})
+ polymorphic_identity='person', properties={'status':relationship(status_mapper)})
engineer_mapper = mapper(Engineer, engineers, inherits=person_mapper, polymorphic_identity='engineer')
manager_mapper = mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager')
- car_mapper = mapper(Car, cars, properties= {'employee':relation(person_mapper), 'status':relation(status_mapper)})
+ car_mapper = mapper(Car, cars, properties= {'employee':relationship(person_mapper), 'status':relationship(status_mapper)})
session = create_session()
with_polymorphic=('*', item_join),
polymorphic_on=base_item_table.c.child_name,
polymorphic_identity='BaseItem',
- properties=dict(collections=relation(Collection, secondary=base_item_collection_table, backref="items")))
+ properties=dict(collections=relationship(Collection, secondary=base_item_collection_table, backref="items")))
mapper(
Item, item_table,
self.label = label
mapper(Person, people, polymorphic_on=people.c._type,polymorphic_identity='person', properties={
- 'tags': relation(Tag, secondary=peopleTags,backref='people', lazy=False)
+ 'tags': relationship(Tag, secondary=peopleTags,backref='people', lazy=False)
})
mapper(Employee, employees, inherits=Person,polymorphic_identity='employee')
mapper(Tag, tags)
mapper(B, tableb)
mapper(A, tablea, with_polymorphic=('*', poly_select), polymorphic_on=poly_select.c.discriminator, properties={
- 'b':relation(B, uselist=False)
+ 'b':relationship(B, uselist=False)
})
mapper(C, tablec, inherits=A,polymorphic_identity='c')
mapper(D, tabled, inherits=C, polymorphic_identity='d')
specification_mapper = mapper(SpecLine, specification_table,
properties=dict(
- master=relation(Assembly,
+ master=relationship(Assembly,
foreign_keys=[specification_table.c.master_id],
primaryjoin=specification_table.c.master_id==products_table.c.product_id,
lazy=True, backref=backref('specification'),
uselist=False),
- slave=relation(Product,
+ slave=relationship(Product,
foreign_keys=[specification_table.c.slave_id],
primaryjoin=specification_table.c.slave_id==products_table.c.product_id,
lazy=True, uselist=False),
specification_mapper = mapper(SpecLine, specification_table,
properties=dict(
- slave=relation(Product,
+ slave=relationship(Product,
foreign_keys=[specification_table.c.slave_id],
primaryjoin=specification_table.c.slave_id==products_table.c.product_id,
lazy=True, uselist=False),
specification_mapper = mapper(SpecLine, specification_table,
properties=dict(
- master=relation(Assembly, lazy=False, uselist=False,
+ master=relationship(Assembly, lazy=False, uselist=False,
foreign_keys=[specification_table.c.master_id],
primaryjoin=specification_table.c.master_id==products_table.c.product_id,
backref=backref('specification', cascade="all, delete-orphan"),
),
- slave=relation(Product, lazy=False, uselist=False,
+ slave=relationship(Product, lazy=False, uselist=False,
foreign_keys=[specification_table.c.slave_id],
primaryjoin=specification_table.c.slave_id==products_table.c.product_id,
),
properties=dict(
name=documents_table.c.name,
data=deferred(documents_table.c.data),
- product=relation(Product, lazy=True, backref=backref('documents', cascade="all, delete-orphan")),
+ product=relationship(Product, lazy=True, backref=backref('documents', cascade="all, delete-orphan")),
),
)
raster_document_mapper = mapper(RasterDocument, inherits=document_mapper,
properties=dict(
name=documents_table.c.name,
data=deferred(documents_table.c.data),
- product=relation(Product, lazy=True, backref=backref('documents', cascade="all, delete-orphan")),
+ product=relationship(Product, lazy=True, backref=backref('documents', cascade="all, delete-orphan")),
),
)
raster_document_mapper = mapper(RasterDocument, inherits=document_mapper,
specification_mapper = mapper(SpecLine, specification_table,
properties=dict(
- master=relation(Assembly, lazy=False, uselist=False,
+ master=relationship(Assembly, lazy=False, uselist=False,
foreign_keys=[specification_table.c.master_id],
primaryjoin=specification_table.c.master_id==products_table.c.product_id,
backref=backref('specification'),
),
- slave=relation(Product, lazy=False, uselist=False,
+ slave=relationship(Product, lazy=False, uselist=False,
foreign_keys=[specification_table.c.slave_id],
primaryjoin=specification_table.c.slave_id==products_table.c.product_id,
),
product_mapper = mapper(Product, products_table,
polymorphic_on=products_table.c.product_type,
polymorphic_identity='product', properties={
- 'documents' : relation(Document, lazy=True,
+ 'documents' : relationship(Document, lazy=True,
backref='product', cascade='all, delete-orphan'),
})
clear_mappers()
mapper(Company, companies, properties={
- 'employees':relation(Person, order_by=people.c.person_id)
+ 'employees':relationship(Person, order_by=people.c.person_id)
})
mapper(Machine, machines)
with_polymorphic=person_with_polymorphic,
polymorphic_on=people.c.type, polymorphic_identity='person', order_by=people.c.person_id,
properties={
- 'paperwork':relation(Paperwork, order_by=paperwork.c.paperwork_id)
+ 'paperwork':relationship(Paperwork, order_by=paperwork.c.paperwork_id)
})
mapper(Engineer, engineers, inherits=Person, polymorphic_identity='engineer', properties={
- 'machines':relation(Machine, order_by=machines.c.machine_id)
+ 'machines':relationship(Machine, order_by=machines.c.machine_id)
})
mapper(Manager, managers, with_polymorphic=manager_with_polymorphic,
inherits=Person, polymorphic_identity='manager')
# compare to entities without related collections to prevent additional lazy SQL from firing on
# loaded entities
- emps_without_relations = [
+ emps_without_relationships = [
Engineer(name="dilbert", engineer_name="dilbert", primary_language="java", status="regular engineer"),
Engineer(name="wally", engineer_name="wally", primary_language="c++", status="regular engineer"),
Boss(name="pointy haired boss", golf_swing="fore", manager_name="pointy", status="da boss"),
Manager(name="dogbert", manager_name="dogbert", status="regular manager"),
Engineer(name="vlad", engineer_name="vlad", primary_language="cobol", status="elbonian engineer")
]
- eq_(sess.query(Person).with_polymorphic('*').all(), emps_without_relations)
+ eq_(sess.query(Person).with_polymorphic('*').all(), emps_without_relationships)
def go():
- eq_(sess.query(Person).with_polymorphic(Engineer).filter(Engineer.primary_language=='java').all(), emps_without_relations[0:1])
+ eq_(sess.query(Person).with_polymorphic(Engineer).filter(Engineer.primary_language=='java').all(), emps_without_relationships[0:1])
self.assert_sql_count(testing.db, go, 1)
sess.expunge_all()
def go():
- eq_(sess.query(Person).with_polymorphic('*').all(), emps_without_relations)
+ eq_(sess.query(Person).with_polymorphic('*').all(), emps_without_relationships)
self.assert_sql_count(testing.db, go, 1)
sess.expunge_all()
def go():
- eq_(sess.query(Person).with_polymorphic(Engineer).all(), emps_without_relations)
+ eq_(sess.query(Person).with_polymorphic(Engineer).all(), emps_without_relationships)
self.assert_sql_count(testing.db, go, 3)
sess.expunge_all()
def go():
- eq_(sess.query(Person).with_polymorphic(Engineer, people.outerjoin(engineers)).all(), emps_without_relations)
+ eq_(sess.query(Person).with_polymorphic(Engineer, people.outerjoin(engineers)).all(), emps_without_relationships)
self.assert_sql_count(testing.db, go, 3)
sess.expunge_all()
def go():
# limit the polymorphic join down to just "Person", overriding select_table
- eq_(sess.query(Person).with_polymorphic(Person).all(), emps_without_relations)
+ eq_(sess.query(Person).with_polymorphic(Person).all(), emps_without_relationships)
self.assert_sql_count(testing.db, go, 6)
- def test_relation_to_polymorphic(self):
+ def test_relationship_to_polymorphic(self):
assert_result = [
Company(name="MegaCorp, Inc.", employees=[
Engineer(name="dilbert", engineer_name="dilbert", primary_language="java", status="regular engineer", machines=[Machine(name="IBM ThinkPad"), Machine(name="IPhone")]),
self.assert_sql_count(testing.db, go, 1)
- def test_query_subclass_join_to_base_relation(self):
+ def test_query_subclass_join_to_base_relationship(self):
sess = create_session()
# non-polymorphic
eq_(sess.query(Engineer).join(Person.paperwork).all(), [e1, e2, e3])
mapper(Engineer, engineers, inherits=Person,
inherit_condition=engineers.c.person_id==people.c.person_id,
polymorphic_identity='engineer', properties={
- 'reports_to':relation(Person, primaryjoin=people.c.person_id==engineers.c.reports_to_id)
+ 'reports_to':relationship(Person, primaryjoin=people.c.person_id==engineers.c.reports_to_id)
})
def test_has(self):
mapper(Engineer, engineers, inherits=Person,
polymorphic_identity='engineer', properties={
- 'reports_to':relation(Manager, primaryjoin=managers.c.person_id==engineers.c.reports_to_id, backref='engineers')
+ 'reports_to':relationship(Manager, primaryjoin=managers.c.person_id==engineers.c.reports_to_id, backref='engineers')
})
def test_has(self):
]
)
- def test_relation_compare(self):
+ def test_relationship_compare(self):
m1 = Manager(name='dogbert')
m2 = Manager(name='foo')
e1 = Engineer(name='dilbert', primary_language='java', reports_to=m1)
pass
mapper(Organization, organizations, properties={
- 'engineers':relation(Engineer, secondary=engineers_to_org, backref='organizations')
+ 'engineers':relationship(Engineer, secondary=engineers_to_org, backref='organizations')
})
mapper(Person, people, polymorphic_on=people.c.type, polymorphic_identity='person')
id = Column(Integer, ForeignKey('parent.id'), primary_key=True)
__mapper_args__ = dict(polymorphic_identity = 'child2')
- Child1.left_child2 = relation(Child2, secondary = secondary_table,
+ Child1.left_child2 = relationship(Child2, secondary = secondary_table,
primaryjoin = Parent.id == secondary_table.c.right_id,
secondaryjoin = Parent.id == secondary_table.c.left_id,
uselist = False, backref="right_children"
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(Parent, parent, properties={
- 'children':relation(Sub)
+ 'children':relationship(Sub)
})
mapper(Base, base, polymorphic_on=base.c.type, polymorphic_identity='b')
mapper(Sub, sub, inherits=Base, polymorphic_identity='s')
def setup_mappers(cls):
mapper(Parent, parent, polymorphic_on=parent.c.type, polymorphic_identity='b')
mapper(Subparent, subparent, inherits=Parent, polymorphic_identity='s', properties={
- 'children':relation(Sub)
+ 'children':relationship(Sub)
})
mapper(Base, base, polymorphic_on=base.c.type, polymorphic_identity='b')
mapper(Sub, sub, inherits=Base, polymorphic_identity='s')
class Report(ComparableEntity): pass
mapper(Report, reports, properties={
- 'employee': relation(Employee, backref='reports')})
+ 'employee': relationship(Employee, backref='reports')})
sess = create_session()
m1 = Manager(name='Tom', manager_data='data1')
class Report(ComparableEntity): pass
mapper(Report, reports, properties={
- 'employee': relation(Employee, backref='reports')})
+ 'employee': relationship(Employee, backref='reports')})
sess = create_session()
m1 = Manager(name='Tom', manager_data='data1')
assert len(rq.join(Report.employee.of_type(Engineer)).all()) == 0
-class RelationToSingleTest(MappedTest):
+class RelationshipToSingleTest(MappedTest):
@classmethod
def define_tables(cls, metadata):
Table('employees', metadata,
@testing.resolve_artifact_names
def test_of_type(self):
mapper(Company, companies, properties={
- 'employees':relation(Employee, backref='company')
+ 'employees':relationship(Employee, backref='company')
})
mapper(Employee, employees, polymorphic_on=employees.c.type)
mapper(Manager, inherits=Employee, polymorphic_identity='manager')
@testing.resolve_artifact_names
- def test_relation_to_subclass(self):
+ def test_relationship_to_subclass(self):
mapper(Company, companies, properties={
- 'engineers':relation(Engineer)
+ 'engineers':relationship(Engineer)
})
mapper(Employee, employees, polymorphic_on=employees.c.type, properties={
- 'company':relation(Company)
+ 'company':relationship(Company)
})
mapper(Manager, inherits=Employee, polymorphic_identity='manager')
mapper(Engineer, inherits=Employee, polymorphic_identity='engineer')
self.temperature = temperature
mapper(WeatherLocation, weather_locations, properties={
- 'reports':relation(Report, backref='location'),
+ 'reports':relationship(Report, backref='location'),
'city': deferred(weather_locations.c.city),
})
from sqlalchemy.test import testing
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from test.orm import _base
from sqlalchemy.test.testing import eq_
mapper(Keyword, keywords)
mapper(KeywordAssociation, item_keywords, properties={
- 'keyword':relation(Keyword, lazy=False)},
+ 'keyword':relationship(Keyword, lazy=False)},
primary_key=[item_keywords.c.item_id, item_keywords.c.keyword_id],
order_by=[item_keywords.c.data])
mapper(Item, items, properties={
- 'keywords' : relation(KeywordAssociation,
+ 'keywords' : relationship(KeywordAssociation,
cascade="all, delete-orphan")
})
from sqlalchemy.test import testing
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, backref, create_session
+from sqlalchemy.orm import mapper, relationship, backref, create_session
from sqlalchemy.test.testing import eq_
from test.orm import _base
mapper(Category, categories)
mapper(Option, options, properties=dict(
- owner=relation(Owner),
- test=relation(Thing)))
+ owner=relationship(Owner),
+ test=relationship(Thing)))
mapper(Thing, tests, properties=dict(
- owner=relation(Owner, backref='tests'),
- category=relation(Category),
- owner_option=relation(Option,
+ owner=relationship(Owner, backref='tests'),
+ category=relationship(Category),
+ owner_option=relationship(Option,
primaryjoin=sa.and_(tests.c.id == options.c.test_id,
tests.c.owner_id == options.c.owner_id),
foreign_keys=[options.c.test_id, options.c.owner_id],
mapper(Left, left)
mapper(Right, right)
mapper(Middle, middle, properties=dict(
- left=relation(Left,
+ left=relationship(Left,
lazy=False,
backref=backref('middle',lazy=False)),
- right=relation(Right,
+ right=relationship(Right,
lazy=False,
backref=backref('middle', lazy=False)))),
def test_nesting_with_functions(self):
mapper(Data, datas)
mapper(Foo, foo, properties={
- 'data': relation(Data,backref=backref('foo',uselist=False))})
+ 'data': relationship(Data,backref=backref('foo',uselist=False))})
mapper(Stat, stats, properties={
- 'data':relation(Data)})
+ 'data':relationship(Data)})
session = create_session()
def test_basic(self):
mapper(Employee, employees)
mapper(Department, departments, properties=dict(
- employees=relation(Employee,
+ employees=relationship(Employee,
lazy=False,
backref='department')))
commentMapper = mapper(Comment, comments)
baseMapper = mapper(Base, base, properties=dict(
- comments=relation(Comment, lazy=False,
+ comments=relationship(Comment, lazy=False,
cascade='all, delete-orphan')))
mapper(Derived, derived, inherits=baseMapper)
p_m = mapper(Part, parts)
mapper(InheritedPart, inherited_part, properties=dict(
- part=relation(Part, lazy=False)))
+ part=relationship(Part, lazy=False)))
d_m = mapper(Design, design, properties=dict(
- inheritedParts=relation(InheritedPart,
+ inheritedParts=relationship(InheritedPart,
cascade="all, delete-orphan",
backref="design")))
mapper(DesignType, design_types)
d_m.add_property(
- "type", relation(DesignType, lazy=False, backref="designs"))
+ "type", relationship(DesignType, lazy=False, backref="designs"))
p_m.add_property(
- "design", relation(
+ "design", relationship(
Design, lazy=False,
backref=backref("parts", cascade="all, delete-orphan")))
mapper(Address, addresses)
mapper(Company, companies, properties={
- 'addresses' : relation(Address, lazy=False)})
+ 'addresses' : relationship(Address, lazy=False)})
mapper(Invoice, invoices, properties={
- 'company': relation(Company, lazy=False)})
+ 'company': relationship(Company, lazy=False)})
a1 = Address(address='a1 address')
a2 = Address(address='a2 address')
mapper(Phone, phone_numbers)
mapper(Address, addresses, properties={
- 'phones': relation(Phone, lazy=False, backref='address',
+ 'phones': relationship(Phone, lazy=False, backref='address',
order_by=phone_numbers.c.phone_id)})
mapper(Company, companies, properties={
- 'addresses': relation(Address, lazy=False, backref='company',
+ 'addresses': relationship(Address, lazy=False, backref='company',
order_by=addresses.c.address_id)})
mapper(Item, items)
mapper(Invoice, invoices, properties={
- 'items': relation(Item, lazy=False, backref='invoice',
+ 'items': relationship(Item, lazy=False, backref='invoice',
order_by=items.c.item_id),
- 'company': relation(Company, lazy=False, backref='invoices')})
+ 'company': relationship(Company, lazy=False, backref='invoices')})
c1 = Company(company_name='company 1', addresses=[
Address(address='a1 address',
jjj = sa.join(task, jj, task.c.id == jj.c.task_id)
mapper(Joined, jjj, properties=dict(
- type=relation(Task_Type, lazy=False)))
+ type=relationship(Task_Type, lazy=False)))
session = create_session()
mapper(Transaction, transactions)
mapper(Entry, entries, properties=dict(
- account=relation(Account,
+ account=relationship(Account,
uselist=False,
backref=backref('entries', lazy=True,
order_by=entries.c.entry_id)),
- transaction=relation(Transaction,
+ transaction=relationship(Transaction,
uselist=False,
backref=backref('entries', lazy=False,
order_by=entries.c.entry_id))))
from sqlalchemy import Integer, String, ForeignKey, Sequence, exc as sa_exc
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session, class_mapper, backref, sessionmaker
+from sqlalchemy.orm import mapper, relationship, create_session, class_mapper, backref, sessionmaker
from sqlalchemy.orm import attributes, exc as orm_exc
from sqlalchemy.test import testing
from sqlalchemy.test.testing import eq_
def setup_mappers(cls):
mapper(Address, addresses)
mapper(User, users, properties = dict(
- addresses = relation(Address, backref="user"),
+ addresses = relationship(Address, backref="user"),
))
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(Address, addresses)
mapper(User, users, properties = {
- 'address':relation(Address, backref=backref("user"), uselist=False)
+ 'address':relationship(Address, backref=backref("user"), uselist=False)
})
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(Address, addresses)
mapper(User, users, properties = {
- 'address':relation(Address, uselist=False)
+ 'address':relationship(Address, uselist=False)
})
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(Address, addresses)
mapper(User, users, properties = {
- 'address':relation(Address, uselist=False,
+ 'address':relationship(Address, uselist=False,
backref=backref('user', single_parent=True, cascade="all, delete-orphan"))
})
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(Item, items, properties={
- 'keyword':relation(Keyword, secondary=item_keywords, uselist=False, backref=backref("item", uselist=False))
+ 'keyword':relationship(Keyword, secondary=item_keywords, uselist=False, backref=backref("item", uselist=False))
})
mapper(Keyword, keywords)
from sqlalchemy.test.testing import assert_raises, assert_raises_message
from sqlalchemy import Integer, String, ForeignKey, Sequence, exc as sa_exc
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session, sessionmaker, class_mapper, backref
+from sqlalchemy.orm import mapper, relationship, create_session, sessionmaker, class_mapper, backref
from sqlalchemy.orm import attributes, exc as orm_exc
from sqlalchemy.test import testing
from sqlalchemy.test.testing import eq_
def setup_mappers(cls):
mapper(Address, addresses)
mapper(User, users, properties = dict(
- addresses = relation(Address, cascade="all, delete-orphan", backref="user"),
- orders = relation(
+ addresses = relationship(Address, cascade="all, delete-orphan", backref="user"),
+ orders = relationship(
mapper(Order, orders), cascade="all, delete-orphan", order_by=orders.c.id)
))
mapper(Dingaling,dingalings, properties={
- 'address':relation(Address)
+ 'address':relationship(Address)
})
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(Address, addresses)
mapper(User, users, properties = {
- 'address':relation(Address, backref=backref("user", single_parent=True), uselist=False)
+ 'address':relationship(Address, backref=backref("user", single_parent=True), uselist=False)
})
@testing.resolve_artifact_names
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(User, users, properties = dict(
- orders = relation(
+ orders = relationship(
mapper(Order, orders), cascade="all, delete-orphan", backref="user")
))
def test_unidirectional_cascade_o2m(self):
mapper(Order, orders)
mapper(User, users, properties = dict(
- orders = relation(
+ orders = relationship(
Order, backref=backref("user", cascade=None))
))
@testing.resolve_artifact_names
def test_unidirectional_cascade_m2o(self):
mapper(Order, orders, properties={
- 'user':relation(User, backref=backref("orders", cascade=None))
+ 'user':relationship(User, backref=backref("orders", cascade=None))
})
mapper(User, users)
@testing.resolve_artifact_names
def test_unidirectional_cascade_m2m(self):
mapper(Item, items, properties={
- 'keywords':relation(Keyword, secondary=item_keywords, cascade="none", backref="items")
+ 'keywords':relationship(Keyword, secondary=item_keywords, cascade="none", backref="items")
})
mapper(Keyword, keywords)
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(User, users, properties = dict(
- orders = relation(
+ orders = relationship(
mapper(Order, orders), cascade="all")
))
def setup_mappers(cls):
mapper(Extra, extra)
mapper(Pref, prefs, properties=dict(
- extra = relation(Extra, cascade="all, delete")
+ extra = relationship(Extra, cascade="all, delete")
))
mapper(User, users, properties = dict(
- pref = relation(Pref, lazy=False, cascade="all, delete-orphan", single_parent=True ),
- foo = relation(Foo) # straight m2o
+ pref = relationship(Pref, lazy=False, cascade="all, delete-orphan", single_parent=True ),
+ foo = relationship(Foo) # straight m2o
))
mapper(Foo, foo)
@classmethod
@testing.resolve_artifact_names
def setup_mappers(cls):
- mapper(T1, t1, properties={'t2': relation(T2, cascade="all")})
- mapper(T2, t2, properties={'t3': relation(T3, cascade="all")})
+ mapper(T1, t1, properties={'t2': relationship(T2, cascade="all")})
+ mapper(T2, t2, properties={'t3': relationship(T3, cascade="all")})
mapper(T3, t3)
@testing.resolve_artifact_names
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(T1, t1, properties=dict(
- t2=relation(T2, cascade="all, delete-orphan", single_parent=True)))
+ t2=relationship(T2, cascade="all, delete-orphan", single_parent=True)))
mapper(T2, t2, properties=dict(
- t3=relation(T3, cascade="all, delete-orphan", single_parent=True, backref=backref('t2', uselist=False))))
+ t3=relationship(T3, cascade="all, delete-orphan", single_parent=True, backref=backref('t2', uselist=False))))
mapper(T3, t3)
@testing.resolve_artifact_names
mapper(A, a, properties={
# if no backref here, delete-orphan failed until [ticket:427] was
# fixed
- 'bs': relation(B, secondary=atob, cascade="all, delete-orphan", single_parent=True)
+ 'bs': relationship(B, secondary=atob, cascade="all, delete-orphan", single_parent=True)
})
mapper(B, b)
mapper(A, a, properties={
# if no backref here, delete-orphan failed until [ticket:427] was
# fixed
- 'bs': relation(B, secondary=atob,
+ 'bs': relationship(B, secondary=atob,
cascade="all, delete-orphan", single_parent=True,lazy="dynamic")
})
mapper(B, b)
mapper(A, a, properties={
# if no backref here, delete-orphan failed until [ticket:427] was
# fixed
- 'bs':relation(B, secondary=atob, cascade="all, delete-orphan", single_parent=True)
+ 'bs':relationship(B, secondary=atob, cascade="all, delete-orphan", single_parent=True)
})
- mapper(B, b, properties={'cs':relation(C, cascade="all, delete-orphan")})
+ mapper(B, b, properties={'cs':relationship(C, cascade="all, delete-orphan")})
mapper(C, c)
sess = create_session()
@testing.resolve_artifact_names
def test_cascade_delete(self):
mapper(A, a, properties={
- 'bs':relation(B, secondary=atob, cascade="all, delete-orphan", single_parent=True)
+ 'bs':relationship(B, secondary=atob, cascade="all, delete-orphan", single_parent=True)
})
mapper(B, b)
@testing.resolve_artifact_names
def test_single_parent_raise(self):
mapper(A, a, properties={
- 'bs':relation(B, secondary=atob, cascade="all, delete-orphan", single_parent=True)
+ 'bs':relationship(B, secondary=atob, cascade="all, delete-orphan", single_parent=True)
})
mapper(B, b)
"""test that setting m2m via a uselist=False backref bypasses the single_parent raise"""
mapper(A, a, properties={
- 'bs':relation(B,
+ 'bs':relationship(B,
secondary=atob,
cascade="all, delete-orphan", single_parent=True,
backref=backref('a', uselist=False))
mapper(Address, addresses)
mapper(User, users, properties=dict(
- addresses=relation(Address, cascade="all,delete-orphan", backref="user")
+ addresses=relationship(Address, cascade="all,delete-orphan", backref="user")
))
s = create_session()
a = Address()
mapper(Address, addresses)
mapper(User, users, properties=dict(
- addresses=relation(Address, cascade="all,delete-orphan", backref="user")
+ addresses=relationship(Address, cascade="all,delete-orphan", backref="user")
))
s = create_session()
def test_nonorphans_ok(self):
mapper(Address, addresses)
mapper(User, users, properties=dict(
- addresses=relation(Address, cascade="all,delete", backref="user")
+ addresses=relationship(Address, cascade="all,delete", backref="user")
))
s = create_session()
u = User(name='u1', addresses=[Address(email_address='ad1')])
mapper(Attribute, attributes)
mapper(Item, items, properties=dict(
- attributes=relation(Attribute, cascade="all,delete-orphan", backref="item")
+ attributes=relationship(Attribute, cascade="all,delete-orphan", backref="item")
))
mapper(Order, orders, properties=dict(
- items=relation(Item, cascade="all,delete-orphan", backref="order")
+ items=relationship(Item, cascade="all,delete-orphan", backref="order")
))
s = create_session()
@testing.resolve_artifact_names
def test_double_parent_expunge_o2m(self):
- """test the delete-orphan uow event for multiple delete-orphan parent relations."""
+ """test the delete-orphan uow event for multiple delete-orphan parent relationships."""
class Customer(_fixtures.Base):
pass
mapper(Customer, customers)
mapper(Account, accounts, properties=dict(
- customers=relation(Customer,
+ customers=relationship(Customer,
cascade="all,delete-orphan",
backref="account")))
mapper(SalesRep, sales_reps, properties=dict(
- customers=relation(Customer,
+ customers=relationship(Customer,
cascade="all,delete-orphan",
backref="sales_rep")))
s = create_session()
@testing.resolve_artifact_names
def test_double_parent_expunge_o2o(self):
- """test the delete-orphan uow event for multiple delete-orphan parent relations."""
+ """test the delete-orphan uow event for multiple delete-orphan parent relationships."""
class Customer(_fixtures.Base):
pass
mapper(Customer, customers)
mapper(Account, accounts, properties=dict(
- customer=relation(Customer,
+ customer=relationship(Customer,
cascade="all,delete-orphan",
backref="account", uselist=False)))
mapper(SalesRep, sales_reps, properties=dict(
- customer=relation(Customer,
+ customer=relationship(Customer,
cascade="all,delete-orphan",
backref="sales_rep", uselist=False)))
s = create_session()
class DoubleParentOrphanTest(_base.MappedTest):
- """test orphan detection for an entity with two parent relations"""
+ """test orphan detection for an entity with two parent relationships"""
@classmethod
def define_tables(cls, metadata):
pass
mapper(Address, addresses)
- mapper(Home, homes, properties={'address':relation(Address, cascade="all,delete-orphan", single_parent=True)})
- mapper(Business, businesses, properties={'address':relation(Address, cascade="all,delete-orphan", single_parent=True)})
+ mapper(Home, homes, properties={'address':relationship(Address, cascade="all,delete-orphan", single_parent=True)})
+ mapper(Business, businesses, properties={'address':relationship(Address, cascade="all,delete-orphan", single_parent=True)})
session = create_session()
h1 = Home(description='home1', address=Address(street='address1'))
pass
mapper(Address, addresses)
- mapper(Home, homes, properties={'address':relation(Address, cascade="all,delete-orphan", single_parent=True)})
- mapper(Business, businesses, properties={'address':relation(Address, cascade="all,delete-orphan", single_parent=True)})
+ mapper(Home, homes, properties={'address':relationship(Address, cascade="all,delete-orphan", single_parent=True)})
+ mapper(Business, businesses, properties={'address':relationship(Address, cascade="all,delete-orphan", single_parent=True)})
session = create_session()
a1 = Address()
pass
mapper(A, table_a, properties={
- 'bs':relation(B, cascade="all, delete-orphan")
+ 'bs':relationship(B, cascade="all, delete-orphan")
})
mapper(B, table_b)
pass
mapper(Base, base, properties={
- 'children':relation(Child, backref='parent')
+ 'children':relationship(Child, backref='parent')
})
mapper(Child, noninh_child)
mapper(Child, inh_child,
inherits=Base,
- properties={'parent': relation(
+ properties={'parent': relationship(
Parent,
backref='children',
primaryjoin=inh_child.c.parent_id == parent.c.id
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table, Column
from sqlalchemy import util, exc as sa_exc
-from sqlalchemy.orm import create_session, mapper, relation, attributes
+from sqlalchemy.orm import create_session, mapper, relationship, attributes
from test.orm import _base
from sqlalchemy.test.testing import eq_, assert_raises
def _test_scalar_mapped(self, collection_class):
mapper(Child, children)
mapper(Parent, parents, properties={
- 'children': relation(Child, collection_class=collection_class,
+ 'children': relationship(Child, collection_class=collection_class,
cascade="all, delete-orphan")})
p = Parent()
def _test_composite_mapped(self, collection_class):
mapper(Child, children)
mapper(Parent, parents, properties={
- 'children': relation(Child, collection_class=collection_class,
+ 'children': relationship(Child, collection_class=collection_class,
cascade="all, delete-orphan")
})
class Bar(BaseObject):
__tablename__ = "bar"
id = Column(Integer(), primary_key=True, test_needs_autoincrement=True)
- foos = relation(Foo, collection_class=collections.column_mapped_collection(Foo.id))
- foos2 = relation(Foo, collection_class=collections.column_mapped_collection((Foo.id, Foo.bar_id)))
+ foos = relationship(Foo, collection_class=collections.column_mapped_collection(Foo.id))
+ foos2 = relationship(Foo, collection_class=collections.column_mapped_collection((Foo.id, Foo.bar_id)))
eq_(Bar.foos.property.collection_class().keyfunc(Foo(id=3)), 3)
eq_(Bar.foos2.property.collection_class().keyfunc(Foo(id=3, bar_id=12)), (3, 12))
pass
mapper(Foo, sometable, properties={
- 'bars':relation(Bar, collection_class=MyList)
+ 'bars':relationship(Bar, collection_class=MyList)
})
mapper(Bar, someothertable)
f = Foo()
class Bar(object):
pass
mapper(Foo, sometable, properties={
- 'bars':relation(Bar, collection_class=set)
+ 'bars':relationship(Bar, collection_class=set)
})
mapper(Bar, someothertable)
f = Foo()
del self[id(item)]
mapper(Foo, sometable, properties={
- 'bars':relation(Bar, collection_class=AppenderDict)
+ 'bars':relationship(Bar, collection_class=AppenderDict)
})
mapper(Bar, someothertable)
f = Foo()
def __init__(self, data): self.data = data
mapper(Foo, sometable, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
collection_class=collections.column_mapped_collection(
someothertable.c.data))
})
pass
mapper(Parent, sometable, properties={
- 'children':relation(Child, collection_class=listcls)
+ 'children':relationship(Child, collection_class=listcls)
})
mapper(Child, someothertable)
return iter(self.data)
mapper(Parent, sometable, properties={
- 'children':relation(Child, collection_class=MyCollection)
+ 'children':relationship(Child, collection_class=MyCollection)
})
mapper(Child, someothertable)
polymorphic_on=order_join.c.type,
polymorphic_identity='order',
properties={
- 'orderproducts': relation(OrderProduct, lazy=True, backref='order')}
+ 'orderproducts': relationship(OrderProduct, lazy=True, backref='order')}
)
mapper(Product, product,
properties={
- 'orderproducts': relation(OrderProduct, lazy=True, backref='product')}
+ 'orderproducts': relationship(OrderProduct, lazy=True, backref='product')}
)
mapper(Employee, employee,
properties={
- 'orders': relation(Order, lazy=True, backref='employee')})
+ 'orders': relationship(Order, lazy=True, backref='employee')})
mapper(OrderProduct, orderproduct)
polymorphic_on=order_join.c.type,
polymorphic_identity='order',
properties={
- 'orderproducts': relation(OrderProduct, lazy=True, backref='product')}
+ 'orderproducts': relationship(OrderProduct, lazy=True, backref='product')}
)
mapper(Product, product,
properties={
- 'orderproducts': relation(OrderProduct, lazy=True, backref='product')}
+ 'orderproducts': relationship(OrderProduct, lazy=True, backref='product')}
)
mapper(OrderProduct, orderproduct)
host_mapper = mapper(Host, host_table)
node_name_mapper = mapper(NodeName, node_name_table,
properties = {
- 'node' : relation(Node, backref=backref('names')),
- 'host' : relation(Host),
+ 'node' : relationship(Node, backref=backref('names')),
+ 'host' : relationship(Host),
}
)
sess = create_session()
class B(object):pass
mapper(A, a, properties={
- 'b':relation(B, backref='a')
+ 'b':relationship(B, backref='a')
})
mapper(B, b, properties={
- 'a':relation(A, backref='b')
+ 'a':relationship(A, backref='b')
})
try:
from sqlalchemy.test import testing
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, backref, create_session
+from sqlalchemy.orm import mapper, relationship, backref, create_session
from sqlalchemy.test.testing import eq_
from sqlalchemy.test.assertsql import RegexSQL, ExactSQL, CompiledSQL, AllOf
from test.orm import _base
@testing.resolve_artifact_names
def testsingle(self):
mapper(C1, t1, properties = {
- 'c1s':relation(C1, cascade="all"),
- 'parent':relation(C1,
+ 'c1s':relationship(C1, cascade="all"),
+ 'parent':relationship(C1,
primaryjoin=t1.c.parent_c1 == t1.c.c1,
remote_side=t1.c.c1,
lazy=True,
test that the circular dependency sort can assemble a many-to-one
dependency processor when only the object on the "many" side is
actually in the list of modified objects. this requires that the
- circular sort add the other side of the relation into the
+ circular sort add the other side of the relationship into the
UOWTransaction so that the dependency operation can be tacked onto it.
This also affects inheritance relationships since they rely upon
"""
mapper(C1, t1, properties={
- 'parent':relation(C1,
+ 'parent':relationship(C1,
primaryjoin=t1.c.parent_c1 == t1.c.c1,
remote_side=t1.c.c1)})
@testing.resolve_artifact_names
def testcycle(self):
mapper(C1, t1, properties = {
- 'c1s' : relation(C1, cascade="all"),
- 'c2s' : relation(mapper(C2, t2), cascade="all, delete-orphan")})
+ 'c1s' : relationship(C1, cascade="all"),
+ 'c2s' : relationship(mapper(C2, t2), cascade="all, delete-orphan")})
a = C1('head c1')
a.c1s.append(C1('child1'))
@testing.resolve_artifact_names
def test_setnull_ondelete(self):
mapper(C1, t1, properties={
- 'children':relation(C1)
+ 'children':relationship(C1)
})
sess = create_session()
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(TT, item, properties={
- 'children': relation(
+ 'children': relationship(
TT,
remote_side=[item.c.parent_uuid],
backref=backref('parent', remote_side=[item.c.uuid]))})
mapper(Parent, parent)
mapper(Child1, child1, inherits=Parent)
mapper(Child2, child2, inherits=Parent, properties=dict(
- child1=relation(Child1,
+ child1=relationship(Child1,
primaryjoin=child2.c.child1_id == child1.c.id)))
@testing.resolve_artifact_names
@testing.resolve_artifact_names
def test_flush(self):
mapper(A, a, properties={
- 'cs':relation(C, primaryjoin=a.c.cid==c.c.id)})
+ 'cs':relationship(C, primaryjoin=a.c.cid==c.c.id)})
mapper(B, b, inherits=A, inherit_condition=b.c.id == a.c.id)
mapper(C, c, properties={
- 'arel':relation(A, primaryjoin=a.c.id == c.c.aid)})
+ 'arel':relationship(A, primaryjoin=a.c.id == c.c.aid)})
sess = create_session()
bobj = B()
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(T1, t1, properties={
- 't2':relation(T2, primaryjoin=t1.c.t2id == t2.c.id)})
+ 't2':relationship(T2, primaryjoin=t1.c.t2id == t2.c.id)})
mapper(T2, t2, properties={
- 't1':relation(T1, primaryjoin=t2.c.t1id == t1.c.id)})
+ 't1':relationship(T1, primaryjoin=t2.c.t1id == t1.c.id)})
mapper(T3, t3, properties={
- 't1':relation(T1),
- 't2':relation(T2)})
+ 't1':relationship(T1),
+ 't2':relationship(T2)})
@testing.resolve_artifact_names
def test_reflush(self):
class BiDirectionalOneToManyTest(_base.MappedTest):
- """tests two mappers with a one-to-many relation to each other."""
+ """tests two mappers with a one-to-many relationship to each other."""
run_define_tables = 'each'
@testing.resolve_artifact_names
def testcycle(self):
mapper(C2, t2, properties={
- 'c1s': relation(C1,
+ 'c1s': relationship(C1,
primaryjoin=t2.c.c1 == t1.c.c2,
uselist=True)})
mapper(C1, t1, properties={
- 'c2s': relation(C2,
+ 'c2s': relationship(C2,
primaryjoin=t1.c.c1 == t2.c.c2,
uselist=True)})
class BiDirectionalOneToManyTest2(_base.MappedTest):
- """Two mappers with a one-to-many relation to each other, with a second one-to-many on one of the mappers"""
+ """Two mappers with a one-to-many relationship to each other, with a second one-to-many on one of the mappers"""
run_define_tables = 'each'
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(C2, t2, properties={
- 'c1s': relation(C1,
+ 'c1s': relationship(C1,
primaryjoin=t2.c.c1 == t1.c.c2,
uselist=True)})
mapper(C1, t1, properties={
- 'c2s': relation(C2,
+ 'c2s': relationship(C2,
primaryjoin=t1.c.c1 == t2.c.c2,
uselist=True),
- 'data': relation(mapper(C1Data, t1_data))})
+ 'data': relationship(mapper(C1Data, t1_data))})
@testing.resolve_artifact_names
def testcycle(self):
"""
mapper(Ball, ball)
mapper(Person, person, properties=dict(
- balls=relation(Ball,
+ balls=relationship(Ball,
primaryjoin=ball.c.person_id == person.c.id,
remote_side=ball.c.person_id),
- favorite=relation(Ball,
+ favorite=relationship(Ball,
primaryjoin=person.c.favorite_ball_id == ball.c.id,
remote_side=ball.c.id)))
"""A cycle between two rows, with a post_update on the many-to-one"""
mapper(Ball, ball)
mapper(Person, person, properties=dict(
- balls=relation(Ball,
+ balls=relationship(Ball,
primaryjoin=ball.c.person_id == person.c.id,
remote_side=ball.c.person_id,
post_update=False,
cascade="all, delete-orphan"),
- favorite=relation(Ball,
+ favorite=relationship(Ball,
primaryjoin=person.c.favorite_ball_id == ball.c.id,
remote_side=person.c.favorite_ball_id,
post_update=True)))
mapper(Ball, ball)
mapper(Person, person, properties=dict(
- balls=relation(Ball,
+ balls=relationship(Ball,
primaryjoin=ball.c.person_id == person.c.id,
remote_side=ball.c.person_id,
cascade="all, delete-orphan",
post_update=True,
backref='person'),
- favorite=relation(Ball,
+ favorite=relationship(Ball,
primaryjoin=person.c.favorite_ball_id == ball.c.id,
remote_side=person.c.favorite_ball_id)))
"""
mapper(Node, node, properties={
- 'children': relation(
+ 'children': relationship(
Node,
primaryjoin=node.c.id==node.c.parent_id,
lazy=True,
cascade="all",
backref=backref("parent", remote_side=node.c.id)
),
- 'prev_sibling': relation(
+ 'prev_sibling': relationship(
Node,
primaryjoin=node.c.prev_sibling_id==node.c.id,
remote_side=node.c.id,
lazy=True,
uselist=False),
- 'next_sibling': relation(
+ 'next_sibling': relationship(
Node,
primaryjoin=node.c.next_sibling_id==node.c.id,
remote_side=node.c.id,
"""
mapper(A, a_table, properties={
- 'foo': relation(A,
+ 'foo': relationship(A,
remote_side=[a_table.c.id],
post_update=True)})
from sqlalchemy.test import testing
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from test.orm import _base
from sqlalchemy.test.testing import eq_
from sqlalchemy import Integer, String, ForeignKey, func
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session, sessionmaker
+from sqlalchemy.orm import mapper, relationship, relation, create_session, sessionmaker
from test.orm import _base
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(User, users_table, properties=dict(
- addresses=relation(Address, backref='user'),
+ addresses=relationship(Address, backref='user'),
))
mapper(Address, addresses_table)
users = session.query(User).filter("name='ed'").all()
assert len(users) == 1 and users[0].name == 'ed'
-
from sqlalchemy.test import testing
from sqlalchemy import Integer, String, ForeignKey, desc, select, func
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session, Query, attributes
+from sqlalchemy.orm import mapper, relationship, create_session, Query, attributes
from sqlalchemy.orm.dynamic import AppenderMixin
from sqlalchemy.test.testing import eq_, AssertsCompiledSQL
from sqlalchemy.util import function_named
@testing.resolve_artifact_names
def test_backref(self):
mapper(Address, addresses, properties={
- 'user':relation(User, backref=backref('addresses', lazy='dynamic'))
+ 'user':relationship(User, backref=backref('addresses', lazy='dynamic'))
})
mapper(User, users)
@testing.resolve_artifact_names
def test_m2m(self):
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, lazy="dynamic",
+ 'items':relationship(Item, secondary=order_items, lazy="dynamic",
backref=backref('orders', lazy="dynamic"))
})
mapper(Item, items)
@testing.resolve_artifact_names
def test_association_nonaliased(self):
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items,
+ 'items':relationship(Item, secondary=order_items,
lazy="dynamic",
order_by=order_items.c.item_id)
})
sess.delete(u)
- # u.addresses relation will have to force the load
+ # u.addresses relationship will have to force the load
# of all addresses so that they can be updated
sess.flush()
sess.close()
sess.delete(u)
- # u.addresses relation will have to force the load
+ # u.addresses relationship will have to force the load
# of all addresses so that they can be updated
sess.flush()
sess.close()
pass
mapper(User, users, properties={
- 'addresses': relation(Address, backref='user', lazy='dynamic')
+ 'addresses': relationship(Address, backref='user', lazy='dynamic')
})
mapper(Address, addresses)
from sqlalchemy.orm import eagerload, deferred, undefer, eagerload_all, backref
from sqlalchemy import Integer, String, Date, ForeignKey, and_, select, func
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session, lazyload, aliased
+from sqlalchemy.orm import mapper, relationship, create_session, lazyload, aliased
from sqlalchemy.test.testing import eq_, assert_raises
from sqlalchemy.test.assertsql import CompiledSQL
from test.orm import _base, _fixtures
@testing.resolve_artifact_names
def test_basic(self):
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), lazy=False, order_by=Address.id)
+ 'addresses':relationship(mapper(Address, addresses), lazy=False, order_by=Address.id)
})
sess = create_session()
q = sess.query(User)
m = mapper(User, users)
sess = create_session()
sess.query(User).all()
- m.add_property("addresses", relation(mapper(Address, addresses)))
+ m.add_property("addresses", relationship(mapper(Address, addresses)))
sess.expunge_all()
def go():
def test_no_orphan(self):
"""An eagerly loaded child object is not marked as an orphan"""
mapper(User, users, properties={
- 'addresses':relation(Address, cascade="all,delete-orphan", lazy=False)
+ 'addresses':relationship(Address, cascade="all,delete-orphan", lazy=False)
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_orderby(self):
mapper(User, users, properties = {
- 'addresses':relation(mapper(Address, addresses), lazy=False, order_by=addresses.c.email_address),
+ 'addresses':relationship(mapper(Address, addresses), lazy=False, order_by=addresses.c.email_address),
})
q = create_session().query(User)
eq_([
@testing.resolve_artifact_names
def test_orderby_multi(self):
mapper(User, users, properties = {
- 'addresses':relation(mapper(Address, addresses), lazy=False, order_by=[addresses.c.email_address, addresses.c.id]),
+ 'addresses':relationship(mapper(Address, addresses), lazy=False, order_by=[addresses.c.email_address, addresses.c.id]),
})
q = create_session().query(User)
eq_([
@testing.resolve_artifact_names
def test_orderby_related(self):
- """A regular mapper select on a single table can order by a relation to a second table"""
+ """A regular mapper select on a single table can order by a relationship to a second table"""
mapper(Address, addresses)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy=False, order_by=addresses.c.id),
+ addresses = relationship(Address, lazy=False, order_by=addresses.c.id),
))
q = create_session().query(User)
def test_orderby_desc(self):
mapper(Address, addresses)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy=False,
+ addresses = relationship(Address, lazy=False,
order_by=[sa.desc(addresses.c.email_address)]),
))
sess = create_session()
mapper(Address, addresses, properties={
'user_id':deferred(addresses.c.user_id),
- 'user':relation(User, lazy=False)
+ 'user':relationship(User, lazy=False)
})
mapper(User, users)
'user_id':deferred(addresses.c.user_id),
})
mapper(User, users, properties={
- 'addresses':relation(Address, lazy=False)})
+ 'addresses':relationship(Address, lazy=False)})
for q in [
sess.query(User).filter(User.id==7),
sa.orm.clear_mappers()
mapper(User, users, properties={
- 'addresses':relation(Address, lazy=False)})
+ 'addresses':relationship(Address, lazy=False)})
mapper(Address, addresses, properties={
'user_id':deferred(addresses.c.user_id),
- 'dingalings':relation(Dingaling, lazy=False)})
+ 'dingalings':relationship(Dingaling, lazy=False)})
mapper(Dingaling, dingalings, properties={
'address_id':deferred(dingalings.c.address_id)})
sess.expunge_all()
mapper(Keyword, keywords)
mapper(Item, items, properties = dict(
- keywords = relation(Keyword, secondary=item_keywords,
+ keywords = relationship(Keyword, secondary=item_keywords,
lazy=False, order_by=keywords.c.id)))
q = create_session().query(Item).order_by(Item.id)
mapper(Keyword, keywords)
mapper(Item, items, properties = dict(
- keywords = relation(Keyword, secondary=item_keywords, lazy=True,
+ keywords = relationship(Keyword, secondary=item_keywords, lazy=True,
order_by=keywords.c.id)))
q = create_session().query(Item)
mapper(Address, addresses)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy=False,
+ addresses = relationship(Address, lazy=False,
backref=sa.orm.backref('user', lazy=False), order_by=Address.id)
))
is_(sa.orm.class_mapper(User).get_property('addresses').lazy, False)
@testing.resolve_artifact_names
def test_double(self):
- """Eager loading with two relations simultaneously, from the same table, using aliases."""
+ """Eager loading with two relationships simultaneously, from the same table, using aliases."""
User, Address, Order = self.classes.get_all(
'User', 'Address', 'Order')
users, addresses, orders = self.tables.get_all(
closed_mapper = mapper(Order, closedorders, non_primary=True)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy=False, order_by=addresses.c.id),
- open_orders = relation(
+ addresses = relationship(Address, lazy=False, order_by=addresses.c.id),
+ open_orders = relationship(
open_mapper,
primaryjoin=sa.and_(openorders.c.isopen == 1,
users.c.id==openorders.c.user_id),
lazy=False, order_by=openorders.c.id),
- closed_orders = relation(
+ closed_orders = relationship(
closed_mapper,
primaryjoin=sa.and_(closedorders.c.isopen == 0,
users.c.id==closedorders.c.user_id),
@testing.resolve_artifact_names
def test_double_same_mappers(self):
- """Eager loading with two relations simulatneously, from the same table, using aliases."""
+ """Eager loading with two relationships simulatneously, from the same table, using aliases."""
User, Address, Order = self.classes.get_all(
'User', 'Address', 'Order')
users, addresses, orders = self.tables.get_all(
mapper(Address, addresses)
mapper(Order, orders, properties={
- 'items': relation(Item, secondary=order_items, lazy=False,
+ 'items': relationship(Item, secondary=order_items, lazy=False,
order_by=items.c.id)})
mapper(Item, items)
mapper(User, users, properties=dict(
- addresses=relation(Address, lazy=False, order_by=addresses.c.id),
- open_orders=relation(
+ addresses=relationship(Address, lazy=False, order_by=addresses.c.id),
+ open_orders=relationship(
Order,
primaryjoin=sa.and_(orders.c.isopen == 1,
users.c.id==orders.c.user_id),
lazy=False, order_by=orders.c.id),
- closed_orders=relation(
+ closed_orders=relationship(
Order,
primaryjoin=sa.and_(orders.c.isopen == 0,
users.c.id==orders.c.user_id),
'users', 'addresses', 'orders')
mapper(User, users, properties={
- 'addresses':relation(Address, lazy=False),
- 'orders':relation(Order, lazy=False)
+ 'addresses':relationship(Address, lazy=False),
+ 'orders':relationship(Order, lazy=False)
})
mapper(Address, addresses)
mapper(Order, orders)
mapper(Item, items)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, lazy=False, order_by=items.c.id)
+ 'items':relationship(Item, secondary=order_items, lazy=False, order_by=items.c.id)
})
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), lazy=False, order_by=addresses.c.id),
- 'orders':relation(Order, lazy=True, order_by=orders.c.id)
+ 'addresses':relationship(mapper(Address, addresses), lazy=False, order_by=addresses.c.id),
+ 'orders':relationship(Order, lazy=True, order_by=orders.c.id)
})
sess = create_session()
s = sa.union_all(u2.select(use_labels=True), u2.select(use_labels=True), u2.select(use_labels=True)).alias('u')
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), lazy=False, order_by=addresses.c.id),
+ 'addresses':relationship(mapper(Address, addresses), lazy=False, order_by=addresses.c.id),
})
sess = create_session()
def test_limit_2(self):
mapper(Keyword, keywords)
mapper(Item, items, properties = dict(
- keywords = relation(Keyword, secondary=item_keywords, lazy=False, order_by=[keywords.c.id]),
+ keywords = relationship(Keyword, secondary=item_keywords, lazy=False, order_by=[keywords.c.id]),
))
sess = create_session()
mapper(Item, items)
mapper(Order, orders, properties = dict(
- items = relation(Item, secondary=order_items, lazy=False)
+ items = relationship(Item, secondary=order_items, lazy=False)
))
mapper(Address, addresses)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy=False, order_by=addresses.c.id),
- orders = relation(Order, lazy=False, order_by=orders.c.id),
+ addresses = relationship(Address, lazy=False, order_by=addresses.c.id),
+ orders = relationship(Order, lazy=False, order_by=orders.c.id),
))
sess = create_session()
sel = sa.select([users, addresses.c.email_address],
users.c.id==addresses.c.user_id).alias('useralias')
mapper(User, sel, properties={
- 'orders':relation(Order, primaryjoin=sel.c.id==orders.c.user_id, lazy=False)
+ 'orders':relationship(Order, primaryjoin=sel.c.id==orders.c.user_id, lazy=False)
})
mapper(Order, orders)
"""test that the subquery wrapping only occurs with limit/offset and m2m or o2m joins present."""
mapper(User, users, properties=odict(
- orders=relation(Order, backref='user')
+ orders=relationship(Order, backref='user')
))
mapper(Order, orders, properties=odict(
- items=relation(Item, secondary=order_items, backref='orders'),
- address=relation(Address)
+ items=relationship(Item, secondary=order_items, backref='orders'),
+ address=relationship(Address)
))
mapper(Address, addresses)
mapper(Item, items)
@testing.resolve_artifact_names
def test_one_to_many_scalar(self):
mapper(User, users, properties = dict(
- address = relation(mapper(Address, addresses), lazy=False, uselist=False)
+ address = relationship(mapper(Address, addresses), lazy=False, uselist=False)
))
q = create_session().query(User)
@testing.resolve_artifact_names
def test_many_to_one(self):
mapper(Address, addresses, properties = dict(
- user = relation(mapper(User, users), lazy=False)
+ user = relationship(mapper(User, users), lazy=False)
))
sess = create_session()
q = sess.query(Address)
# use a primaryjoin intended to defeat SA's usage of
# query.get() for a many-to-one lazyload
mapper(Order, orders, properties = dict(
- address = relation(mapper(Address, addresses),
+ address = relationship(mapper(Address, addresses),
primaryjoin=and_(
addresses.c.id==orders.c.address_id,
addresses.c.email_address != None
contains a many-to-many relationship to a third object."""
mapper(User, users, properties={
- 'orders':relation(Order, lazy=False, order_by=orders.c.id)
+ 'orders':relationship(Order, lazy=False, order_by=orders.c.id)
})
mapper(Item, items)
mapper(Order, orders, properties = dict(
- items = relation(Item, secondary=order_items, lazy=False, order_by=items.c.id)
+ items = relationship(Item, secondary=order_items, lazy=False, order_by=items.c.id)
))
q = create_session().query(User)
mapper(Order, orders)
mapper(User, users, properties={
- 'orders':relation(Order, backref='user', lazy=False, order_by=orders.c.id),
- 'max_order':relation(
+ 'orders':relationship(Order, backref='user', lazy=False, order_by=orders.c.id),
+ 'max_order':relationship(
mapper(Order, max_orders, non_primary=True),
lazy=False, uselist=False)
})
"""test that multiple rows received by a uselist=False raises a warning."""
mapper(User, users, properties={
- 'order':relation(Order, uselist=False)
+ 'order':relationship(Order, uselist=False)
})
mapper(Order, orders)
s = create_session()
@testing.resolve_artifact_names
def test_wide(self):
- mapper(Order, orders, properties={'items':relation(Item, secondary=order_items, lazy=False,
+ mapper(Order, orders, properties={'items':relationship(Item, secondary=order_items, lazy=False,
order_by=items.c.id)})
mapper(Item, items)
mapper(User, users, properties = dict(
- addresses = relation(mapper(Address, addresses), lazy = False, order_by=addresses.c.id),
- orders = relation(Order, lazy = False, order_by=orders.c.id),
+ addresses = relationship(mapper(Address, addresses), lazy = False, order_by=addresses.c.id),
+ orders = relationship(Order, lazy = False, order_by=orders.c.id),
))
q = create_session().query(User)
l = q.all()
s = sa.select([orders], orders.c.isopen==1).alias('openorders')
mapper(Order, s, properties={
- 'user':relation(User, lazy=False)
+ 'user':relationship(User, lazy=False)
})
mapper(User, users)
mapper(Item, items)
"""test that eager loading uses aliases to insulate the eager load from regular criterion against those tables."""
mapper(User, users, properties = dict(
- addresses = relation(mapper(Address, addresses), lazy=False, order_by=addresses.c.id)
+ addresses = relationship(mapper(Address, addresses), lazy=False, order_by=addresses.c.id)
))
q = create_session().query(User)
l = q.filter(addresses.c.email_address == 'ed@lala.com').filter(
@testing.resolve_artifact_names
def test_inner_join(self):
mapper(User, users, properties = dict(
- addresses = relation(mapper(Address, addresses), lazy=False, innerjoin=True, order_by=addresses.c.id)
+ addresses = relationship(mapper(Address, addresses), lazy=False, innerjoin=True, order_by=addresses.c.id)
))
sess = create_session()
eq_(
@testing.resolve_artifact_names
def test_inner_join_options(self):
mapper(User, users, properties = dict(
- orders =relation(Order, backref=backref('user', innerjoin=True), order_by=orders.c.id)
+ orders =relationship(Order, backref=backref('user', innerjoin=True), order_by=orders.c.id)
))
mapper(Order, orders, properties=dict(
- items=relation(Item, secondary=order_items, order_by=items.c.id)
+ items=relationship(Item, secondary=order_items, order_by=items.c.id)
))
mapper(Item, items)
sess = create_session()
@testing.resolve_artifact_names
def test_mapper_configured(self):
mapper(User, users, properties={
- 'addresses':relation(Address, lazy=False),
- 'orders':relation(Order)
+ 'addresses':relationship(Address, lazy=False),
+ 'orders':relationship(Order)
})
mapper(Address, addresses)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, lazy=False, order_by=items.c.id)
+ 'items':relationship(Item, secondary=order_items, lazy=False, order_by=items.c.id)
})
mapper(Item, items)
@testing.resolve_artifact_names
def test_options(self):
mapper(User, users, properties={
- 'addresses':relation(Address),
- 'orders':relation(Order)
+ 'addresses':relationship(Address),
+ 'orders':relationship(Order)
})
mapper(Address, addresses)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, order_by=items.c.id)
+ 'items':relationship(Item, secondary=order_items, order_by=items.c.id)
})
mapper(Item, items)
class B(_base.ComparableEntity):pass
mapper(A, a, properties={
- 'bs':relation(B, secondary=m2m, lazy=False, order_by=m2m.c.id)
+ 'bs':relationship(B, secondary=m2m, lazy=False, order_by=m2m.c.id)
})
mapper(B, b)
self.children.append(node)
mapper(Node, nodes, properties={
- 'children':relation(Node, lazy=False, join_depth=3, order_by=nodes.c.id)
+ 'children':relationship(Node, lazy=False, join_depth=3, order_by=nodes.c.id)
})
sess = create_session()
n1 = Node(data='n1')
self.children.append(node)
mapper(Node, nodes, properties={
- 'children':relation(Node, lazy=False, join_depth=1, order_by=nodes.c.id)
+ 'children':relationship(Node, lazy=False, join_depth=1, order_by=nodes.c.id)
})
sess = create_session()
n1 = Node(data='n1')
self.children.append(node)
mapper(Node, nodes, properties={
- 'children':relation(Node, lazy=False, join_depth=3, order_by=nodes.c.id),
+ 'children':relationship(Node, lazy=False, join_depth=3, order_by=nodes.c.id),
'data':deferred(nodes.c.data)
})
sess = create_session()
self.children.append(node)
mapper(Node, nodes, properties={
- 'children':relation(Node, lazy=True, order_by=nodes.c.id)
+ 'children':relationship(Node, lazy=True, order_by=nodes.c.id)
}, order_by=nodes.c.id)
sess = create_session()
n1 = Node(data='n1')
self.children.append(node)
mapper(Node, nodes, properties={
- 'children':relation(Node, lazy=False)
+ 'children':relationship(Node, lazy=False)
})
sess = create_session()
n1 = Node(data='n1')
mapper(A,a_table)
mapper(B,b_table,properties = {
- 'parent_b1': relation(B,
+ 'parent_b1': relationship(B,
remote_side = [b_table.c.id],
primaryjoin = (b_table.c.parent_b1_id ==b_table.c.id),
order_by = b_table.c.id
),
- 'parent_z': relation(A,lazy = True),
- 'parent_b2': relation(B,
+ 'parent_z': relationship(A,lazy = True),
+ 'parent_b2': relationship(B,
remote_side = [b_table.c.id],
primaryjoin = (b_table.c.parent_b2_id ==b_table.c.id),
order_by = b_table.c.id
pass
mapper(Widget, widget, properties={
- 'children': relation(Widget, secondary=widget_rel,
+ 'children': relationship(Widget, secondary=widget_rel,
primaryjoin=widget_rel.c.parent_id==widget.c.id,
secondaryjoin=widget_rel.c.child_id==widget.c.id,
lazy=False, join_depth=1,
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user'),
- 'orders':relation(Order, backref='user'), # o2m, m2o
+ 'addresses':relationship(Address, backref='user'),
+ 'orders':relationship(Order, backref='user'), # o2m, m2o
})
mapper(Address, addresses)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, order_by=items.c.id), #m2m
+ 'items':relationship(Item, secondary=order_items, order_by=items.c.id), #m2m
})
mapper(Item, items, properties={
- 'keywords':relation(Keyword, secondary=item_keywords) #m2m
+ 'keywords':relationship(Keyword, secondary=item_keywords) #m2m
})
mapper(Keyword, keywords)
mapper(T, t1, polymorphic_on=t1.c.type, polymorphic_identity='t1')
mapper(SubT, None, inherits=T, polymorphic_identity='subt1', properties={
- 't2s':relation(SubT2, lazy=False, backref=sa.orm.backref('subt', lazy=False))
+ 't2s':relationship(SubT2, lazy=False, backref=sa.orm.backref('subt', lazy=False))
})
mapper(T2, t2, polymorphic_on=t2.c.type, polymorphic_identity='t2')
mapper(SubT2, None, inherits=T2, polymorphic_identity='subt2')
mapper(User, users_table, properties={
- 'tags': relation(Tag, backref='user', lazy=False),
+ 'tags': relationship(Tag, backref='user', lazy=False),
'query_score': sa.orm.column_property(user_score),
})
class CorrelatedSubqueryTest(_base.MappedTest):
"""tests for #946, #947, #948.
- The "users" table is joined to "stuff", and the relation
+ The "users" table is joined to "stuff", and the relationship
would like to pull only the "stuff" entry with the most recent date.
Exercises a variety of ways to configure this.
if ondate:
mapper(User, users, properties={
- 'stuff':relation(Stuff, primaryjoin=and_(users.c.id==stuff.c.user_id, stuff.c.date==stuff_view))
+ 'stuff':relationship(Stuff, primaryjoin=and_(users.c.id==stuff.c.user_id, stuff.c.date==stuff_view))
})
else:
mapper(User, users, properties={
- 'stuff':relation(Stuff, primaryjoin=and_(users.c.id==stuff.c.user_id, stuff.c.id==stuff_view))
+ 'stuff':relationship(Stuff, primaryjoin=and_(users.c.id==stuff.c.user_id, stuff.c.id==stuff_view))
})
sess = create_session()
from sqlalchemy import Integer, String, ForeignKey, exc as sa_exc
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session, \
+from sqlalchemy.orm import mapper, relationship, create_session, \
attributes, deferred, exc as orm_exc, defer, undefer,\
strategies, state, lazyload
from test.orm import _base, _fixtures
@testing.resolve_artifact_names
def test_expire(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user'),
+ 'addresses':relationship(Address, backref='user'),
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_lazyload_autoflushes(self):
mapper(User, users, properties={
- 'addresses':relation(Address, order_by=addresses.c.email_address)
+ 'addresses':relationship(Address, order_by=addresses.c.email_address)
})
mapper(Address, addresses)
s = create_session(autoflush=True, autocommit=False)
"""test graceful failure for currently unsupported immediate refresh of a collection"""
mapper(User, users, properties={
- 'addresses':relation(Address, order_by=addresses.c.email_address)
+ 'addresses':relationship(Address, order_by=addresses.c.email_address)
})
mapper(Address, addresses)
s = create_session(autoflush=True, autocommit=False)
@testing.resolve_artifact_names
def test_expire_cascade(self):
mapper(User, users, properties={
- 'addresses':relation(Address, cascade="all, refresh-expire")
+ 'addresses':relationship(Address, cascade="all, refresh-expire")
})
mapper(Address, addresses)
s = create_session()
@testing.resolve_artifact_names
def test_expired_lazy(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user'),
+ 'addresses':relationship(Address, backref='user'),
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_expired_eager(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', lazy=False),
+ 'addresses':relationship(Address, backref='user', lazy=False),
})
mapper(Address, addresses)
def go():
assert u.addresses[0].email_address == 'jack@bean.com'
assert u.name == 'jack'
- # two loads, since relation() + scalar are
+ # two loads, since relationship() + scalar are
# separate right now on per-attribute load
self.assert_sql_count(testing.db, go, 2)
assert 'name' in u.__dict__
sess.query(User).filter_by(id=7).one()
assert u.addresses[0].email_address == 'jack@bean.com'
assert u.name == 'jack'
- # one load, since relation() + scalar are
+ # one load, since relationship() + scalar are
# together when eager load used with Query
self.assert_sql_count(testing.db, go, 1)
@testing.resolve_artifact_names
- def test_relation_changes_preserved(self):
+ def test_relationship_changes_preserved(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', lazy=False),
+ 'addresses':relationship(Address, backref='user', lazy=False),
})
mapper(Address, addresses)
sess = create_session()
@testing.resolve_artifact_names
def test_eagerload_props_dontload(self):
- # relations currently have to load separately from scalar instances.
+ # relationships currently have to load separately from scalar instances.
# the use case is: expire "addresses". then access it. lazy load
# fires off to load "addresses", but needs foreign key or primary key
# attributes in order to lazy load; hits those attributes, such as
# "figure out" that the operation should be aborted right now.
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', lazy=False),
+ 'addresses':relationship(Address, backref='user', lazy=False),
})
mapper(Address, addresses)
sess = create_session()
@testing.resolve_artifact_names
def test_partial_expire_lazy(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user'),
+ 'addresses':relationship(Address, backref='user'),
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_partial_expire_eager(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', lazy=False),
+ 'addresses':relationship(Address, backref='user', lazy=False),
})
mapper(Address, addresses)
#self.assert_sql_count(testing.db, go, 0)
@testing.resolve_artifact_names
- def test_relations_load_on_query(self):
+ def test_relationships_load_on_query(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user'),
+ 'addresses':relationship(Address, backref='user'),
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_eagerload_query_refreshes(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', lazy=False),
+ 'addresses':relationship(Address, backref='user', lazy=False),
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_expire_all(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', lazy=False),
+ 'addresses':relationship(Address, backref='user', lazy=False),
})
mapper(Address, addresses)
def test_state_noload_to_lazy(self):
"""Behavioral test to verify the current activity of loader callables."""
- mapper(User, users, properties={'addresses':relation(Address, lazy=None)})
+ mapper(User, users, properties={'addresses':relationship(Address, lazy=None)})
mapper(Address, addresses)
sess = create_session()
@testing.resolve_artifact_names
def test_expired_pending(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user'),
+ 'addresses':relationship(Address, backref='user'),
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_refresh(self):
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), backref='user')
+ 'addresses':relationship(mapper(Address, addresses), backref='user')
})
s = create_session()
u = s.query(User).get(7)
fire the lazy loader or create any problems"""
s = create_session()
- mapper(User, users, properties={'addresses':relation(mapper(Address, addresses))})
+ mapper(User, users, properties={'addresses':relationship(mapper(Address, addresses))})
q = s.query(User).options(sa.orm.lazyload('addresses'))
u = q.filter(users.c.id==8).first()
def go():
"""test that a refresh/expire operation loads rows properly and sends correct "isnew" state to eager loaders"""
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), lazy=False)
+ 'addresses':relationship(mapper(Address, addresses), lazy=False)
})
s = create_session()
s = create_session()
mapper(Address, addresses)
- mapper(User, users, properties = dict(addresses=relation(Address,cascade="all, delete-orphan",lazy=False)) )
+ mapper(User, users, properties = dict(addresses=relationship(Address,cascade="all, delete-orphan",lazy=False)) )
u = User()
u.name='Justin'
from sqlalchemy import Integer, String, ForeignKey, MetaData, func
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from sqlalchemy.test.testing import eq_
from test.orm import _base, _fixtures
eq_(res.count(), 1)
-class RelationsTest(_fixtures.FixtureTest):
+class RelationshipsTest(_fixtures.FixtureTest):
run_setup_mappers = 'once'
run_inserts = 'once'
run_deletes = None
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(User, users, properties={
- 'orders':relation(mapper(Order, orders, properties={
- 'addresses':relation(mapper(Address, addresses))}))})
+ 'orders':relationship(mapper(Order, orders, properties={
+ 'addresses':relationship(mapper(Address, addresses))}))})
@testing.resolve_artifact_names
from sqlalchemy import MetaData, Integer, ForeignKey, util
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session, attributes, class_mapper, clear_mappers
+from sqlalchemy.orm import mapper, relationship, create_session, attributes, class_mapper, clear_mappers
from sqlalchemy.test.testing import eq_, ne_
from sqlalchemy.util import function_named
from test.orm import _base
Column('t1_id', Integer, ForeignKey('t1.id')))
class A(object): pass
class B(object): pass
- mapper(A, t1, properties=dict(bs=relation(B)))
+ mapper(A, t1, properties=dict(bs=relationship(B)))
mapper(B, t2)
a = A()
for base in object, Base:
class A(base): pass
class B(base): pass
- mapper(A, t1, properties=dict(bs=relation(B, backref='a')))
+ mapper(A, t1, properties=dict(bs=relationship(B, backref='a')))
mapper(B, t2)
b = B()
class A(base): pass
class B(base): pass
mapper(A, t1)
- mapper(B, t2, properties=dict(a=relation(A, backref='bs')))
+ mapper(B, t2, properties=dict(a=relationship(A, backref='bs')))
a = A()
b = B()
from sqlalchemy.types import TypeDecorator
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from sqlalchemy.test.testing import eq_
from test.orm import _base, _fixtures
@testing.resolve_artifact_names
def test_basic(self):
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), lazy=True)
+ 'addresses':relationship(mapper(Address, addresses), lazy=True)
})
sess = create_session()
q = sess.query(User)
"""test the error raised when parent object is not bound."""
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), lazy=True)
+ 'addresses':relationship(mapper(Address, addresses), lazy=True)
})
sess = create_session()
q = sess.query(User)
@testing.resolve_artifact_names
def test_orderby(self):
mapper(User, users, properties = {
- 'addresses':relation(mapper(Address, addresses), lazy=True, order_by=addresses.c.email_address),
+ 'addresses':relationship(mapper(Address, addresses), lazy=True, order_by=addresses.c.email_address),
})
q = create_session().query(User)
assert [
@testing.resolve_artifact_names
def test_orderby_secondary(self):
- """tests that a regular mapper select on a single table can order by a relation to a second table"""
+ """tests that a regular mapper select on a single table can order by a relationship to a second table"""
mapper(Address, addresses)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy=True),
+ addresses = relationship(Address, lazy=True),
))
q = create_session().query(User)
l = q.filter(users.c.id==addresses.c.user_id).order_by(addresses.c.email_address).all()
mapper(Address, addresses)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy=True, order_by=[sa.desc(addresses.c.email_address)]),
+ addresses = relationship(Address, lazy=True, order_by=[sa.desc(addresses.c.email_address)]),
))
sess = create_session()
assert [
"""test that a lazily loaded child object is not marked as an orphan"""
mapper(User, users, properties={
- 'addresses':relation(Address, cascade="all,delete-orphan", lazy=True)
+ 'addresses':relationship(Address, cascade="all,delete-orphan", lazy=True)
})
mapper(Address, addresses)
mapper(Item, items)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, lazy=True)
+ 'items':relationship(Item, secondary=order_items, lazy=True)
})
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), lazy=True),
- 'orders':relation(Order, lazy=True)
+ 'addresses':relationship(mapper(Address, addresses), lazy=True),
+ 'orders':relationship(Order, lazy=True)
})
sess = create_session()
def test_distinct(self):
mapper(Item, items)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, lazy=True)
+ 'items':relationship(Item, secondary=order_items, lazy=True)
})
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), lazy=True),
- 'orders':relation(Order, lazy=True)
+ 'addresses':relationship(mapper(Address, addresses), lazy=True),
+ 'orders':relationship(Order, lazy=True)
})
sess = create_session()
"""test that multiple rows received by a uselist=False raises a warning."""
mapper(User, users, properties={
- 'order':relation(Order, uselist=False)
+ 'order':relationship(Order, uselist=False)
})
mapper(Order, orders)
s = create_session()
@testing.resolve_artifact_names
def test_one_to_many_scalar(self):
mapper(User, users, properties = dict(
- address = relation(mapper(Address, addresses), lazy=True, uselist=False)
+ address = relationship(mapper(Address, addresses), lazy=True, uselist=False)
))
q = create_session().query(User)
l = q.filter(users.c.id == 7).all()
mapper(Address, addresses, primary_key=[addresses.c.user_id, addresses.c.email_address])
mapper(User, users, properties = dict(
- address = relation(Address, uselist=False,
+ address = relationship(Address, uselist=False,
primaryjoin=sa.and_(users.c.id==addresses.c.user_id, addresses.c.email_address=='ed@bettyboop.com')
)
))
@testing.resolve_artifact_names
def test_double(self):
- """tests lazy loading with two relations simulatneously, from the same table, using aliases. """
+ """tests lazy loading with two relationships simulatneously, from the same table, using aliases. """
openorders = sa.alias(orders, 'openorders')
closedorders = sa.alias(orders, 'closedorders')
open_mapper = mapper(Order, openorders, non_primary=True)
closed_mapper = mapper(Order, closedorders, non_primary=True)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy = True),
- open_orders = relation(open_mapper, primaryjoin = sa.and_(openorders.c.isopen == 1, users.c.id==openorders.c.user_id), lazy=True),
- closed_orders = relation(closed_mapper, primaryjoin = sa.and_(closedorders.c.isopen == 0, users.c.id==closedorders.c.user_id), lazy=True)
+ addresses = relationship(Address, lazy = True),
+ open_orders = relationship(open_mapper, primaryjoin = sa.and_(openorders.c.isopen == 1, users.c.id==openorders.c.user_id), lazy=True),
+ closed_orders = relationship(closed_mapper, primaryjoin = sa.and_(closedorders.c.isopen == 0, users.c.id==closedorders.c.user_id), lazy=True)
))
q = create_session().query(User)
mapper(Keyword, keywords)
mapper(Item, items, properties = dict(
- keywords = relation(Keyword, secondary=item_keywords, lazy=True),
+ keywords = relationship(Keyword, secondary=item_keywords, lazy=True),
))
q = create_session().query(Item)
addresses.c.user_id==users.c.id
):
mapper(Address, addresses, properties = dict(
- user = relation(mapper(User, users), lazy=True, primaryjoin=pj)
+ user = relationship(mapper(User, users), lazy=True, primaryjoin=pj)
))
sess = create_session()
)
mapper(Address, addresses, properties = dict(
- user = relation(mapper(User, users))
+ user = relationship(mapper(User, users))
))
sess = create_session(bind=testing.db)
@testing.resolve_artifact_names
def test_many_to_one(self):
mapper(Address, addresses, properties = dict(
- user = relation(mapper(User, users), lazy=True)
+ user = relationship(mapper(User, users), lazy=True)
))
sess = create_session()
q = sess.query(Address)
@testing.resolve_artifact_names
def test_backrefs_dont_lazyload(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user')
+ 'addresses':relationship(Address, backref='user')
})
mapper(Address, addresses)
sess = create_session()
mapper(User, users)
mapper(Address, addresses, properties={
- 'user':relation(User)
+ 'user':relationship(User)
})
sess = create_session()
stuff_view = sa.select([stuff.c.id]).where(stuff.c.user_id==user_t.c.id).correlate(user_t).order_by(sa.desc(stuff.c.date)).limit(1)
mapper(User, user_t, properties={
- 'stuff':relation(Stuff, primaryjoin=sa.and_(user_t.c.id==stuff.c.user_id, stuff.c.id==(stuff_view.as_scalar())))
+ 'stuff':relationship(Stuff, primaryjoin=sa.and_(user_t.c.id==stuff.c.user_id, stuff.c.id==(stuff_view.as_scalar())))
})
sess = create_session()
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from test.orm import _base
class Information(object):
pass
- class Relation(object):
+ class Relationship(object):
pass
class Data(object):
session = create_session()
mapper(Data, data)
- mapper(Relation, rels, properties={
- 'datas': relation(Data,
+ mapper(Relationship, rels, properties={
+ 'datas': relationship(Data,
primaryjoin=sa.and_(
rels.c.info_pk ==
data.c.info_pk,
data.c.timeval <= rels.c.finish),
foreign_keys=[data.c.info_pk])})
mapper(Information, infos, properties={
- 'rels': relation(Relation)
+ 'rels': relationship(Relationship)
})
info = session.query(Information).get(1)
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from test.orm import _base
@testing.resolve_artifact_names
def test_error(self):
mapper(Place, place, properties={
- 'transitions':relation(Transition, secondary=place_input, backref='places')
+ 'transitions':relationship(Transition, secondary=place_input, backref='places')
})
mapper(Transition, transition, properties={
- 'places':relation(Place, secondary=place_input, backref='transitions')
+ 'places':relationship(Place, secondary=place_input, backref='transitions')
})
assert_raises_message(sa.exc.ArgumentError, "Error creating backref",
sa.orm.compile_mappers)
Place.mapper = mapper(Place, place)
- Place.mapper.add_property('places', relation(
+ Place.mapper.add_property('places', relationship(
Place.mapper, secondary=place_place, primaryjoin=place.c.place_id==place_place.c.pl1_id,
secondaryjoin=place.c.place_id==place_place.c.pl2_id,
order_by=place_place.c.pl2_id,
@testing.resolve_artifact_names
def test_double(self):
- """test that a mapper can have two eager relations to the same table, via
+ """test that a mapper can have two eager relationships to the same table, via
two different association tables. aliases are required."""
Place.mapper = mapper(Place, place, properties = {
- 'thingies':relation(mapper(PlaceThingy, place_thingy), lazy=False)
+ 'thingies':relationship(mapper(PlaceThingy, place_thingy), lazy=False)
})
Transition.mapper = mapper(Transition, transition, properties = dict(
- inputs = relation(Place.mapper, place_output, lazy=False),
- outputs = relation(Place.mapper, place_input, lazy=False),
+ inputs = relationship(Place.mapper, place_output, lazy=False),
+ outputs = relationship(Place.mapper, place_input, lazy=False),
)
)
"""tests a many-to-many backrefs"""
Place.mapper = mapper(Place, place)
Transition.mapper = mapper(Transition, transition, properties = dict(
- inputs = relation(Place.mapper, place_output, lazy=True, backref='inputs'),
- outputs = relation(Place.mapper, place_input, lazy=True, backref='outputs'),
+ inputs = relationship(Place.mapper, place_output, lazy=True, backref='inputs'),
+ outputs = relationship(Place.mapper, place_input, lazy=True, backref='outputs'),
)
)
mapper(Student, student)
mapper(Course, course, properties={
- 'students': relation(Student, enroll, backref='courses')})
+ 'students': relationship(Student, enroll, backref='courses')})
sess = create_session()
s1 = Student('Student1')
mapper(Student, student)
mapper(Course, course, properties={
- 'students': relation(Student, enroll, backref='courses')})
+ 'students': relationship(Student, enroll, backref='courses')})
sess = create_session()
s1 = Student("s1")
mapper(Student, student)
mapper(Course, course, properties = {
- 'students': relation(Student, enroll, lazy=True,
+ 'students': relationship(Student, enroll, lazy=True,
backref='courses')})
sess = create_session()
mapper(B, b)
mapper(A, a, properties={
- 'tbs': relation(B, primaryjoin=sa.and_(b.c.a1 == a.c.a1,
+ 'tbs': relationship(B, primaryjoin=sa.and_(b.c.a1 == a.c.a1,
b.c.b2 == True),
lazy=False)})
mapper(C, c, properties={
- 'a1s': relation(A, secondary=c2a1, lazy=False),
- 'a2s': relation(A, secondary=c2a2, lazy=False)})
+ 'a1s': relationship(A, secondary=c2a1, lazy=False),
+ 'a2s': relationship(A, secondary=c2a2, lazy=False)})
assert create_session().query(C).with_labels().statement is not None
from sqlalchemy import MetaData, Integer, String, ForeignKey, func, util
from sqlalchemy.test.schema import Table, Column
from sqlalchemy.engine import default
-from sqlalchemy.orm import mapper, relation, backref, create_session, class_mapper, compile_mappers, reconstructor, validates, aliased
-from sqlalchemy.orm import defer, deferred, synonym, attributes, column_property, composite, relation, dynamic_loader, comparable_property,AttributeExtension
+from sqlalchemy.orm import mapper, relationship, backref, create_session, class_mapper, compile_mappers, reconstructor, validates, aliased
+from sqlalchemy.orm import defer, deferred, synonym, attributes, column_property, composite, relationship, dynamic_loader, comparable_property,AttributeExtension
from sqlalchemy.test.testing import eq_, AssertsCompiledSQL
from test.orm import _base, _fixtures
from sqlalchemy.test.assertsql import AllOf, CompiledSQL
mapper(Address, addresses)
mapper(User, users,
properties={
- 'addresses':relation(Address, backref='email_address')
+ 'addresses':relationship(Address, backref='email_address')
})
assert_raises(sa.exc.ArgumentError, sa.orm.compile_mappers)
def test_bad_cascade(self):
mapper(Address, addresses)
assert_raises(sa.exc.ArgumentError,
- relation, Address, cascade="fake, all, delete-orphan")
+ relationship, Address, cascade="fake, all, delete-orphan")
@testing.resolve_artifact_names
def test_exceptions_sticky(self):
"""test preservation of mapper compile errors raised during hasattr()."""
mapper(Address, addresses, properties={
- 'user':relation(User)
+ 'user':relationship(User)
})
hasattr(Address.user, 'property')
assert sa.orm.mapperlib._new_mappers is False
m = mapper(Address, addresses, properties={
- 'user': relation(User, backref="addresses")})
+ 'user': relationship(User, backref="addresses")})
assert m.compiled is False
assert sa.orm.mapperlib._new_mappers is True
@testing.resolve_artifact_names
def test_props(self):
m = mapper(User, users, properties = {
- 'addresses' : relation(mapper(Address, addresses))
+ 'addresses' : relationship(mapper(Address, addresses))
}).compile()
assert User.addresses.property is m.get_property('addresses')
@testing.resolve_artifact_names
def test_compile_on_prop_1(self):
mapper(User, users, properties = {
- 'addresses' : relation(mapper(Address, addresses))
+ 'addresses' : relationship(mapper(Address, addresses))
})
User.addresses.any(Address.email_address=='foo@bar.com')
@testing.resolve_artifact_names
def test_compile_on_prop_2(self):
mapper(User, users, properties = {
- 'addresses' : relation(mapper(Address, addresses))
+ 'addresses' : relationship(mapper(Address, addresses))
})
eq_(str(User.id == 3), str(users.c.id==3))
mapper(Foo, addresses, inherits=User)
ext_list = [AttributeExtension()]
m.add_property('somename', column_property(users.c.name, extension=ext_list))
- m.add_property('orders', relation(Order, extension=ext_list, backref='user'))
+ m.add_property('orders', relationship(Order, extension=ext_list, backref='user'))
assert len(ext_list) == 1
assert Foo.orders.impl.extensions is User.orders.impl.extensions
m.add_property('_name', deferred(users.c.name))
m.add_property('name', synonym('_name'))
- m.add_property('addresses', relation(Address))
+ m.add_property('addresses', relationship(Address))
m.add_property('uc_name', sa.orm.comparable_property(UCComparator))
m.add_property('uc_name2', sa.orm.comparable_property(
UCComparator, User.uc_name2))
# later, backref sets up the prop
mapper(User, users, properties={
- 'addresses':relation(Address, backref='_user')
+ 'addresses':relationship(Address, backref='_user')
})
sess = create_session()
pass
mapper(Node, t, properties={
- '_children':relation(Node, backref=backref('_parent', remote_side=t.c.id)),
+ '_children':relationship(Node, backref=backref('_parent', remote_side=t.c.id)),
'children':synonym('_children'),
'parent':synonym('_parent')
})
mapper(Address, addresses)
try:
mapper(User, users, non_primary=True, properties={
- 'addresses':relation(Address)
+ 'addresses':relationship(Address)
}).compile()
assert False
except sa.exc.ArgumentError, e:
- assert "Attempting to assign a new relation 'addresses' to a non-primary mapper on class 'User'" in str(e)
+ assert "Attempting to assign a new relationship 'addresses' to a non-primary mapper on class 'User'" in str(e)
@testing.resolve_artifact_names
def test_illegal_non_primary_2(self):
include_properties=('id', 'type', 'name'))
e_m = mapper(Employee, inherits=p_m, polymorphic_identity='employee',
properties={
- 'boss': relation(Manager, backref=backref('peon', ), remote_side=t.c.id)
+ 'boss': relationship(Manager, backref=backref('peon', ), remote_side=t.c.id)
},
exclude_properties=('vendor_id',))
mapper(Item, items)
mapper(Order, orders, properties=dict(
- items=relation(Item, order_items)))
+ items=relationship(Item, order_items)))
mapper(User, users, properties=dict(
- orders=relation(Order)))
+ orders=relationship(Order)))
session = create_session()
l = (session.query(User).
def test_many_to_many_count(self):
mapper(Keyword, keywords)
mapper(Item, items, properties=dict(
- keywords = relation(Keyword, item_keywords, lazy=True)))
+ keywords = relationship(Keyword, item_keywords, lazy=True)))
session = create_session()
q = (session.query(Item).
def go():
mapper(User, users,
properties=dict(
- name=relation(mapper(Address, addresses))))
+ name=relationship(mapper(Address, addresses))))
assert_raises(sa.exc.ArgumentError, go)
mapper(User, users,
exclude_properties=['name'],
properties=dict(
- name=relation(mapper(Address, addresses))))
+ name=relationship(mapper(Address, addresses))))
assert bool(User.name)
"""The column being named elsewhere also cancels the error,"""
mapper(User, users,
properties=dict(
- name=relation(mapper(Address, addresses)),
+ name=relationship(mapper(Address, addresses)),
foo=users.c.name))
@testing.resolve_artifact_names
uname = extendedproperty(_get_name, _set_name)
mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=True),
+ addresses = relationship(mapper(Address, addresses), lazy=True),
uname = synonym('name'),
adlist = synonym('addresses'),
adname = synonym('addresses')
mapper(Address, addresses)
mapper(User, users, properties = {
- 'addresses':relation(Address, lazy=True),
+ 'addresses':relationship(Address, lazy=True),
'name':synonym('_name', map_column=True)
})
sa.orm.clear_mappers()
mapper(User, users, properties={
- 'addresses':relation(Address)
+ 'addresses':relationship(Address)
})
assert_raises(sa.orm.exc.UnmappedClassError, sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_synonym_options(self):
mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=True,
+ addresses = relationship(mapper(Address, addresses), lazy=True,
order_by=addresses.c.id),
adlist = synonym('addresses')))
@testing.resolve_artifact_names
def test_eager_options(self):
- """A lazy relation can be upgraded to an eager relation."""
+ """A lazy relationship can be upgraded to an eager relationship."""
mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses),
+ addresses = relationship(mapper(Address, addresses),
order_by=addresses.c.id)))
sess = create_session()
@testing.resolve_artifact_names
def test_eager_options_with_limit(self):
mapper(User, users, properties=dict(
- addresses=relation(mapper(Address, addresses), lazy=True)))
+ addresses=relationship(mapper(Address, addresses), lazy=True)))
sess = create_session()
u = (sess.query(User).
@testing.resolve_artifact_names
def test_lazy_options_with_limit(self):
mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=False)))
+ addresses = relationship(mapper(Address, addresses), lazy=False)))
sess = create_session()
u = (sess.query(User).
@testing.resolve_artifact_names
def test_eager_degrade(self):
- """An eager relation automatically degrades to a lazy relation if eager columns are not available"""
+ """An eager relationship automatically degrades to a lazy relationship if eager columns are not available"""
mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=False)))
+ addresses = relationship(mapper(Address, addresses), lazy=False)))
sess = create_session()
# first test straight eager load, 1 statement
mapper(Keyword, keywords)
mapper(Item, items, properties=dict(
- keywords=relation(Keyword, secondary=item_keywords,
+ keywords=relationship(Keyword, secondary=item_keywords,
lazy=False,
order_by=item_keywords.c.keyword_id)))
mapper(Order, orders, properties=dict(
- items=relation(Item, secondary=order_items, lazy=False,
+ items=relationship(Item, secondary=order_items, lazy=False,
order_by=order_items.c.item_id)))
mapper(User, users, properties=dict(
- addresses=relation(Address, lazy=False,
+ addresses=relationship(Address, lazy=False,
order_by=addresses.c.id),
- orders=relation(Order, lazy=False,
+ orders=relationship(Order, lazy=False,
order_by=orders.c.id)))
sess = create_session()
@testing.resolve_artifact_names
def test_lazy_options(self):
- """An eager relation can be upgraded to a lazy relation."""
+ """An eager relationship can be upgraded to a lazy relationship."""
mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=False)
+ addresses = relationship(mapper(Address, addresses), lazy=False)
))
sess = create_session()
@testing.resolve_artifact_names
def test_option_propagate(self):
mapper(User, users, properties=dict(
- orders = relation(Order)
+ orders = relationship(Order)
))
mapper(Order, orders, properties=dict(
- items = relation(Item, secondary=order_items)
+ items = relationship(Item, secondary=order_items)
))
mapper(Item, items)
mapper(Keyword, keywords)
mapper(Item, items, properties=dict(
- keywords=relation(Keyword, item_keywords,
+ keywords=relationship(Keyword, item_keywords,
order_by=item_keywords.c.item_id)))
mapper(Order, orders, properties=dict(
- items=relation(Item, order_items,
+ items=relationship(Item, order_items,
order_by=items.c.id)))
mapper(User, users, order_by=users.c.id, properties=dict(
- orders=relation(Order, order_by=orders.c.id)))
+ orders=relationship(Order, order_by=orders.c.id)))
@testing.resolve_artifact_names
def test_deep_options_1(self):
assert '@' in ad.email_address
return ad
- mapper(User, users, properties={'addresses':relation(Address)})
+ mapper(User, users, properties={'addresses':relationship(Address)})
mapper(Address, addresses)
sess = create_session()
u1 = User(name='edward')
(deferred, users.c.name),
(synonym, 'name'),
(composite, DummyComposite, users.c.id, users.c.name),
- (relation, Address),
+ (relationship, Address),
(backref, 'address'),
(comparable_property, ),
(dynamic_loader, Address)
self.assert_compile(aliased(User).name == 'ed', "foobar(users_1.name) = foobar(:foobar_1)", dialect=default.DefaultDialect())
@testing.resolve_artifact_names
- def test_relation(self):
+ def test_relationship(self):
from sqlalchemy.orm.properties import PropertyLoader
class MyFactory(PropertyLoader.Comparator):
mapper(User, users)
mapper(Address, addresses, properties={
- 'user':relation(User, comparator_factory=MyFactory,
+ 'user':relationship(User, comparator_factory=MyFactory,
backref=backref("addresses", comparator_factory=MyFactory2)
)
}
mapper(Item, items, properties=dict(
description=deferred(items.c.description)))
mapper(Order, orders, properties=dict(
- items=relation(Item, secondary=order_items)))
+ items=relationship(Item, secondary=order_items)))
mapper(User, users, properties=dict(
- orders=relation(Order, order_by=orders.c.id)))
+ orders=relationship(Order, order_by=orders.c.id)))
sess = create_session()
q = sess.query(User).order_by(User.id)
class Related(_base.ComparableEntity):
pass
mapper(Base, base, polymorphic_on=base.c.type, properties={
- 'related':relation(Related, uselist=False)
+ 'related':relationship(Related, uselist=False)
})
mapper(Child1, child1, inherits=Base, polymorphic_identity='child1', properties={
- 'child2':relation(Child2, primaryjoin=child1.c.child2id==base.c.id, foreign_keys=child1.c.child2id)
+ 'child2':relationship(Child2, primaryjoin=child1.c.child2id==base.c.id, foreign_keys=child1.c.child2id)
})
mapper(Child2, child2, inherits=Base, polymorphic_identity='child2')
mapper(Related, related)
class Human(_base.BasicEntity): pass
class Thing(_base.BasicEntity): pass
- mapper(Human, human, properties={"thing": relation(Thing)})
+ mapper(Human, human, properties={"thing": relationship(Thing)})
mapper(Thing, thing, properties={"name": deferred(thing.c.name)})
@classmethod
self.end = end
mapper(Graph, graphs, properties={
- 'edges':relation(Edge)
+ 'edges':relationship(Edge)
})
mapper(Edge, edges, properties={
'start':sa.orm.composite(Point, edges.c.x1, edges.c.y1),
self.end = end
mapper(Graph, graphs, properties={
- 'edges':relation(Edge)
+ 'edges':relationship(Edge)
})
mapper(Edge, edges, properties={
'start':sa.orm.composite(Point, edges.c.x1, edges.c.y1),
def test_basic(self):
"""A basic one-to-many lazy load"""
m = mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=None)
+ addresses = relationship(mapper(Address, addresses), lazy=None)
))
q = create_session().query(m)
l = [None]
@testing.resolve_artifact_names
def test_options(self):
m = mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=None)
+ addresses = relationship(mapper(Address, addresses), lazy=None)
))
q = create_session().query(m).options(sa.orm.lazyload('addresses'))
l = [None]
Ext, methods = self.extension()
mapper(Item, items, extension=Ext() , properties={
- 'keywords': relation(Keyword, secondary=item_keywords)})
+ 'keywords': relationship(Keyword, secondary=item_keywords)})
mapper(Keyword, keywords, extension=Ext())
sess = create_session()
pass
mapper(H1, ht1, properties={
- 'h2s': relation(H2, backref='h1'),
- 'h3s': relation(H3, secondary=ht4, backref='h1s'),
- 'h1s': relation(H1, secondary=ht5, backref='parent_h1'),
- 't6a': relation(H6, backref='h1a',
- primaryjoin=ht1.c.id==ht6.c.ht1a_id),
- 't6b': relation(H6, backref='h1b',
- primaryjoin=ht1.c.id==ht6.c.ht1b_id),
+ 'h2s': relationship(H2, backref='h1'),
+ 'h3s': relationship(H3, secondary=ht4, backref='h1s'),
+ 'h1s': relationship(H1, secondary=ht5, backref='parent_h1'),
+ 't6a': relationship(H6, backref='h1a',
+ primaryjoin=ht1.c.id==ht6.c.ht1a_id),
+ 't6b': relationship(H6, backref='h1b',
+ primaryjoin=ht1.c.id==ht6.c.ht1b_id),
})
mapper(H2, ht2)
mapper(H3, ht3)
mapper(Cartographer, cartographers, properties=dict(
query=cartographers.c.quip))
mapper(Map, maps, properties=dict(
- mapper=relation(Cartographer, backref='maps')))
+ mapper=relationship(Cartographer, backref='maps')))
c = Cartographer(name='Lenny', alias='The Dude',
query='Where be dragons?')
import operator
from sqlalchemy.test import testing
from sqlalchemy.util import OrderedSet
-from sqlalchemy.orm import mapper, relation, create_session, PropComparator, \
+from sqlalchemy.orm import mapper, relationship, create_session, PropComparator, \
synonym, comparable_property, sessionmaker, attributes
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy.orm.interfaces import MapperOption
@testing.resolve_artifact_names
def test_transient_to_pending_collection(self):
mapper(User, users, properties={
- 'addresses': relation(Address, backref='user',
+ 'addresses': relationship(Address, backref='user',
collection_class=OrderedSet)})
mapper(Address, addresses)
on_load = self.on_load_tracker(User)
@testing.resolve_artifact_names
def test_transient_to_persistent_collection(self):
mapper(User, users, properties={
- 'addresses':relation(Address,
+ 'addresses':relationship(Address,
backref='user',
collection_class=OrderedSet,
order_by=addresses.c.id,
@testing.resolve_artifact_names
def test_detached_to_persistent_collection(self):
mapper(User, users, properties={
- 'addresses':relation(Address,
+ 'addresses':relationship(Address,
backref='user',
order_by=addresses.c.id,
collection_class=OrderedSet)})
@testing.resolve_artifact_names
def test_unsaved_cascade(self):
- """Merge of a transient entity with two child transient entities, with a bidirectional relation."""
+ """Merge of a transient entity with two child transient entities, with a bidirectional relationship."""
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses),
+ 'addresses':relationship(mapper(Address, addresses),
cascade="all", backref="user")
})
on_load = self.on_load_tracker(User)
@testing.resolve_artifact_names
def test_merge_irregular_collection(self):
mapper(User, users, properties={
- 'addresses': relation(
+ 'addresses': relationship(
mapper(Address, addresses),
backref='user',
collection_class=attribute_mapped_collection('email_address')),
"""Merge of a persistent entity with two child persistent entities."""
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), backref='user')
+ 'addresses':relationship(mapper(Address, addresses), backref='user')
})
on_load = self.on_load_tracker(User)
self.on_load_tracker(Address, on_load)
eq_(on_load.called, 21)
@testing.resolve_artifact_names
- def test_no_relation_cascade(self):
- """test that merge doesn't interfere with a relation()
+ def test_no_relationship_cascade(self):
+ """test that merge doesn't interfere with a relationship()
target that specifically doesn't include 'merge' cascade.
"""
mapper(Address, addresses, properties={
- 'user':relation(User, cascade="save-update")
+ 'user':relationship(User, cascade="save-update")
})
mapper(User, users)
sess = create_session()
def test_one_to_many_cascade(self):
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses))})
+ 'addresses':relationship(mapper(Address, addresses))})
on_load = self.on_load_tracker(User)
self.on_load_tracker(Address, on_load)
@testing.resolve_artifact_names
def test_many_to_one_cascade(self):
mapper(Address, addresses, properties={
- 'user':relation(User)
+ 'user':relationship(User)
})
mapper(User, users)
def test_many_to_many_cascade(self):
mapper(Order, orders, properties={
- 'items':relation(mapper(Item, items), secondary=order_items)})
+ 'items':relationship(mapper(Item, items), secondary=order_items)})
on_load = self.on_load_tracker(Order)
self.on_load_tracker(Item, on_load)
def test_one_to_one_cascade(self):
mapper(User, users, properties={
- 'address':relation(mapper(Address, addresses),uselist = False)
+ 'address':relationship(mapper(Address, addresses),uselist = False)
})
on_load = self.on_load_tracker(User)
self.on_load_tracker(Address, on_load)
@testing.resolve_artifact_names
def test_value_to_none(self):
mapper(User, users, properties={
- 'address':relation(mapper(Address, addresses),uselist = False, backref='user')
+ 'address':relationship(mapper(Address, addresses),uselist = False, backref='user')
})
sess = sessionmaker()()
u = User(id=7, name="fred", address=Address(id=1, email_address='foo@bar.com'))
@testing.resolve_artifact_names
def test_no_load_with_backrefs(self):
- """load=False populates relations in both directions without requiring a load"""
+ """load=False populates relationships in both directions without requiring a load"""
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses), backref='user')
+ 'addresses':relationship(mapper(Address, addresses), backref='user')
})
u = User(id=7, name='fred', addresses=[
"""
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses))
+ 'addresses':relationship(mapper(Address, addresses))
})
sess = create_session()
u = User()
@testing.resolve_artifact_names
def test_no_load_sets_backrefs(self):
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses),backref='user')})
+ 'addresses':relationship(mapper(Address, addresses),backref='user')})
sess = create_session()
u = User()
"""
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses),
+ 'addresses':relationship(mapper(Address, addresses),
backref='user', cascade="all, delete-orphan")})
sess = create_session()
u = User()
s = create_session(autoflush=True)
mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses),backref='user')})
+ 'addresses':relationship(mapper(Address, addresses),backref='user')})
a1 = Address(user=s.merge(User(id=1, name='ed')), email_address='x')
before_id = id(a1.user)
def test_cascades_dont_autoflush(self):
sess = create_session(autoflush=True)
m = mapper(User, users, properties={
- 'addresses':relation(mapper(Address, addresses),backref='user')})
+ 'addresses':relationship(mapper(Address, addresses),backref='user')})
user = User(id=8, name='fred', addresses=[Address(email_address='user')])
merged_user = sess.merge(user)
assert merged_user in sess.new
@testing.resolve_artifact_names
def test_cascades_dont_autoflush_2(self):
mapper(User, users, properties={
- 'addresses':relation(Address,
+ 'addresses':relationship(Address,
backref='user',
cascade="all, delete-orphan")
})
from sqlalchemy.test import testing
from sqlalchemy import Integer, String, ForeignKey, Unicode
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from sqlalchemy.test.testing import eq_
from test.orm import _base
@testing.resolve_artifact_names
def _test_onetomany(self, passive_updates):
mapper(User, users, properties={
- 'addresses':relation(Address, passive_updates=passive_updates)
+ 'addresses':relationship(Address, passive_updates=passive_updates)
})
mapper(Address, addresses)
def _test_manytoone(self, passive_updates):
mapper(User, users)
mapper(Address, addresses, properties={
- 'user':relation(User, passive_updates=passive_updates)
+ 'user':relationship(User, passive_updates=passive_updates)
})
sess = create_session()
@testing.resolve_artifact_names
def _test_onetoone(self, passive_updates):
mapper(User, users, properties={
- "address":relation(Address, passive_updates=passive_updates, uselist=False)
+ "address":relationship(Address, passive_updates=passive_updates, uselist=False)
})
mapper(Address, addresses)
def _test_bidirectional(self, passive_updates):
mapper(User, users)
mapper(Address, addresses, properties={
- 'user':relation(User, passive_updates=passive_updates,
+ 'user':relationship(User, passive_updates=passive_updates,
backref='addresses')})
sess = create_session()
@testing.resolve_artifact_names
def _test_manytomany(self, passive_updates):
mapper(User, users, properties={
- 'items':relation(Item, secondary=users_to_items, backref='users',
+ 'items':relationship(Item, secondary=users_to_items, backref='users',
passive_updates=passive_updates)})
mapper(Item, items)
@testing.resolve_artifact_names
def test_onetomany(self):
mapper(Node, nodes, properties={
- 'children': relation(Node,
+ 'children': relationship(Node,
backref=sa.orm.backref('parentnode',
remote_side=nodes.c.name,
passive_updates=False),
@testing.resolve_artifact_names
def _test_onetomany(self, passive_updates):
mapper(User, users, properties={
- 'addresses':relation(Address, passive_updates=passive_updates)})
+ 'addresses':relationship(Address, passive_updates=passive_updates)})
mapper(Address, addresses)
sess = create_session()
"""
mapper(User, users, properties={
- 'addresses':relation(Address, passive_updates=passive_updates)})
+ 'addresses':relationship(Address, passive_updates=passive_updates)})
mapper(Address, addresses)
sess = create_session()
def test_rowswitch_doesntfire(self):
mapper(User, users)
mapper(Address, addresses, properties={
- 'user':relation(User, passive_updates=True)
+ 'user':relationship(User, passive_updates=True)
})
sess = create_session()
"""
mapper(User, users, properties={
- 'addresses':relation(Address, passive_updates=passive_updates)})
+ 'addresses':relationship(Address, passive_updates=passive_updates)})
mapper(Address, addresses)
sess = create_session()
mapper(Person, person, polymorphic_on=person.c.type,
polymorphic_identity='person', passive_updates=passive_updates)
mapper(Engineer, engineer, inherits=Person, polymorphic_identity='engineer', properties={
- 'boss':relation(Manager,
+ 'boss':relationship(Manager,
primaryjoin=manager.c.name==engineer.c.boss_name,
passive_updates=passive_updates
)
mapper(Person, person, polymorphic_on=person.c.type,
polymorphic_identity='person', passive_updates=passive_updates)
mapper(Engineer, engineer, inherits=Person, polymorphic_identity='engineer', properties={
- 'boss':relation(Manager,
+ 'boss':relationship(Manager,
primaryjoin=manager.c.name==engineer.c.boss_name,
passive_updates=passive_updates
)
from sqlalchemy.test import testing
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session
+from sqlalchemy.orm import mapper, relationship, create_session
from test.orm import _base
mapper(Jack, jack,
order_by=[jack.c.number],
properties=dict(
- port=relation(Port, backref='jack',
+ port=relationship(Port, backref='jack',
uselist=False,
)),
)
from sqlalchemy.test.testing import assert_raises_message
from sqlalchemy import Integer, String, ForeignKey, exc
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session, \
+from sqlalchemy.orm import mapper, relationship, create_session, \
sessionmaker, attributes, interfaces,\
clear_mappers, exc as orm_exc,\
compile_mappers
@testing.resolve_artifact_names
def test_transient(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref="user")
+ 'addresses':relationship(Address, backref="user")
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_serialize_path(self):
umapper = mapper(User, users, properties={
- 'addresses':relation(Address, backref="user")
+ 'addresses':relationship(Address, backref="user")
})
amapper = mapper(Address, addresses)
- # this is a "relation" path with mapper, key, mapper, key
+ # this is a "relationship" path with mapper, key, mapper, key
p1 = (umapper, 'addresses', amapper, 'email_address')
eq_(
interfaces.deserialize_path(interfaces.serialize_path(p1)),
def test_class_deferred_cols(self):
mapper(User, users, properties={
'name':sa.orm.deferred(users.c.name),
- 'addresses':relation(Address, backref="user")
+ 'addresses':relationship(Address, backref="user")
})
mapper(Address, addresses, properties={
'email_address':sa.orm.deferred(addresses.c.email_address)
@testing.resolve_artifact_names
def test_instance_deferred_cols(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref="user")
+ 'addresses':relationship(Address, backref="user")
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_pickle_protocols(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref="user")
+ 'addresses':relationship(Address, backref="user")
})
mapper(Address, addresses)
@testing.resolve_artifact_names
def test_options_with_descriptors(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref="user")
+ 'addresses':relationship(Address, backref="user")
})
mapper(Address, addresses)
sess = create_session()
@testing.resolve_artifact_names
def test_one(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref="user")
+ 'addresses':relationship(Address, backref="user")
})
mapper(Address, addresses)
data = \
@testing.resolve_artifact_names
def test_two(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref="user")
+ 'addresses':relationship(Address, backref="user")
})
mapper(Address, addresses)
data = \
@classmethod
def setup_mappers(cls):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', order_by=addresses.c.id),
- 'orders':relation(Order, backref='user', order_by=orders.c.id), # o2m, m2o
+ 'addresses':relationship(Address, backref='user', order_by=addresses.c.id),
+ 'orders':relationship(Order, backref='user', order_by=orders.c.id), # o2m, m2o
})
mapper(Address, addresses, properties={
- 'dingaling':relation(Dingaling, uselist=False, backref="address") #o2o
+ 'dingaling':relationship(Dingaling, uselist=False, backref="address") #o2o
})
mapper(Dingaling, dingalings)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, order_by=items.c.id), #m2m
- 'address':relation(Address), # m2o
+ 'items':relationship(Item, secondary=order_items, order_by=items.c.id), #m2m
+ 'address':relationship(Address), # m2o
})
mapper(Item, items, properties={
- 'keywords':relation(Keyword, secondary=item_keywords) #m2m
+ 'keywords':relationship(Keyword, secondary=item_keywords) #m2m
})
mapper(Keyword, keywords)
mapper(Node, nodes, properties={
- 'children':relation(Node,
+ 'children':relationship(Node,
backref=backref('parent', remote_side=[nodes.c.id])
)
})
self._test(None == Address.user, "addresses.user_id IS NULL")
self._test(~(None == Address.user), "addresses.user_id IS NOT NULL")
- def test_relation(self):
+ def test_relationship(self):
self._test(User.addresses.any(Address.id==17),
"EXISTS (SELECT 1 "
"FROM addresses "
self._test(Address.user != None, "addresses.user_id IS NOT NULL")
- def test_selfref_relation(self):
+ def test_selfref_relationship(self):
nalias = aliased(Node)
# auto self-referential aliasing
self._test(User.id.in_(['a', 'b']),
"users.id IN (:id_1, :id_2)")
- def test_in_on_relation_not_supported(self):
+ def test_in_on_relationship_not_supported(self):
assert_raises(NotImplementedError, Address.user.in_, [User(id=5)])
def test_neg(self):
pass
mapper(Company, companies, properties={
- 'employees':relation(Person, order_by=people.c.person_id)
+ 'employees':relationship(Person, order_by=people.c.person_id)
})
mapper(Machine, machines)
mapper(Person, people,
polymorphic_on=people.c.type, polymorphic_identity='person', order_by=people.c.person_id,
properties={
- 'paperwork':relation(Paperwork, order_by=paperwork.c.paperwork_id)
+ 'paperwork':relationship(Paperwork, order_by=paperwork.c.paperwork_id)
})
mapper(Engineer, engineers, inherits=Person, polymorphic_identity='engineer', properties={
- 'machines':relation(Machine, order_by=machines.c.machine_id)
+ 'machines':relationship(Machine, order_by=machines.c.machine_id)
})
mapper(Manager, managers,
inherits=Person, polymorphic_identity='manager')
class T2(object):pass
mapper(T1, t1, properties={
- 't2s_1':relation(T2, secondary=t1t2_1),
- 't2s_2':relation(T2, secondary=t1t2_2),
+ 't2s_1':relationship(T2, secondary=t1t2_1),
+ 't2s_2':relationship(T2, secondary=t1t2_2),
})
mapper(T2, t2)
def setup_mappers(cls):
mapper(User, users, properties={
'name_syn':synonym('name'),
- 'addresses':relation(Address),
- 'orders':relation(Order, backref='user'), # o2m, m2o
+ 'addresses':relationship(Address),
+ 'orders':relationship(Order, backref='user'), # o2m, m2o
'orders_syn':synonym('orders')
})
mapper(Address, addresses)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items), #m2m
- 'address':relation(Address), # m2o
+ 'items':relationship(Item, secondary=order_items), #m2m
+ 'address':relationship(Address), # m2o
'items_syn':synonym('items')
})
mapper(Item, items, properties={
- 'keywords':relation(Keyword, secondary=item_keywords) #m2m
+ 'keywords':relationship(Keyword, secondary=item_keywords) #m2m
})
mapper(Keyword, keywords)
mapper(Address, addresses)
mapper(User, users, properties=dict(
- addresses=relation(Address)))
+ addresses=relationship(Address)))
@testing.resolve_artifact_names
def test_one(self):
def test_replace_with_select(self):
mapper(User, users, properties = {
- 'addresses':relation(Address)
+ 'addresses':relationship(Address)
})
mapper(Address, addresses)
def test_join(self):
mapper(User, users, properties = {
- 'addresses':relation(Address)
+ 'addresses':relationship(Address)
})
mapper(Address, addresses)
def test_more_joins(self):
mapper(User, users, properties={
- 'orders':relation(Order, backref='user'), # o2m, m2o
+ 'orders':relationship(Order, backref='user'), # o2m, m2o
})
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, order_by=items.c.id), #m2m
+ 'items':relationship(Item, secondary=order_items, order_by=items.c.id), #m2m
})
mapper(Item, items, properties={
- 'keywords':relation(Keyword, secondary=item_keywords, order_by=keywords.c.id) #m2m
+ 'keywords':relationship(Keyword, secondary=item_keywords, order_by=keywords.c.id) #m2m
})
mapper(Keyword, keywords)
def test_replace_with_eager(self):
mapper(User, users, properties = {
- 'addresses':relation(Address, order_by=addresses.c.id)
+ 'addresses':relationship(Address, order_by=addresses.c.id)
})
mapper(Address, addresses)
"""test aliasing of joins with a custom join condition"""
mapper(Address, addresses)
mapper(Order, orders, properties={
- 'items':relation(Item, secondary=order_items, lazy=True, order_by=items.c.id),
+ 'items':relationship(Item, secondary=order_items, lazy=True, order_by=items.c.id),
})
mapper(Item, items)
mapper(User, users, properties = dict(
- addresses = relation(Address, lazy=True),
- open_orders = relation(Order, primaryjoin = and_(orders.c.isopen == 1, users.c.id==orders.c.user_id), lazy=True),
- closed_orders = relation(Order, primaryjoin = and_(orders.c.isopen == 0, users.c.id==orders.c.user_id), lazy=True)
+ addresses = relationship(Address, lazy=True),
+ open_orders = relationship(Order, primaryjoin = and_(orders.c.isopen == 1, users.c.id==orders.c.user_id), lazy=True),
+ closed_orders = relationship(Order, primaryjoin = and_(orders.c.isopen == 0, users.c.id==orders.c.user_id), lazy=True)
))
q = create_session().query(User)
self.children.append(node)
mapper(Node, nodes, properties={
- 'children':relation(Node, lazy=True, join_depth=3,
+ 'children':relationship(Node, lazy=True, join_depth=3,
backref=backref('parent', remote_side=[nodes.c.id])
)
})
pass
mapper(Node, nodes, properties={
- 'children':relation(Node, lazy=True, secondary=node_to_nodes,
+ 'children':relationship(Node, lazy=True, secondary=node_to_nodes,
primaryjoin=nodes.c.id==node_to_nodes.c.left_node_id,
secondaryjoin=nodes.c.id==node_to_nodes.c.right_node_id,
)
})
mapper(Address, addresses, properties={
- 'user':relation(User)
+ 'user':relationship(User)
})
sess = create_session()
# therefore the long standing practice of eager adapters being "chained" has been removed
# since its unnecessary and breaks this exact condition.
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', order_by=addresses.c.id),
+ 'addresses':relationship(Address, backref='user', order_by=addresses.c.id),
'concat': column_property((users.c.id * 2)),
'count': column_property(select([func.count(addresses.c.id)], users.c.id==addresses.c.user_id).correlate(users))
})
mapper(Address, addresses)
mapper(Order, orders, properties={
- 'address':relation(Address), # m2o
+ 'address':relationship(Address), # m2o
})
sess = create_session()
pass
mapper(Base, base, properties={
- 'sub1':relation(Sub1),
- 'sub2':relation(Sub2)
+ 'sub1':relationship(Sub1),
+ 'sub2':relationship(Sub2)
})
mapper(Sub1, sub1)
def setup_mappers(cls):
mapper(User, users)
mapper(Document, documents, properties={
- 'user': relation(User, lazy=False, backref=backref('documents', lazy=True))
+ 'user': relationship(User, lazy=False, backref=backref('documents', lazy=True))
})
@testing.resolve_artifact_names
eq_(rowcount, 3)
@testing.resolve_artifact_names
- def test_update_with_eager_relations(self):
+ def test_update_with_eager_relationships(self):
self.insert_documents()
sess = create_session(bind=testing.db, autocommit=False)
eq_(sess.query(User.age).order_by(User.id).all(), zip([25,37,29,27]))
@testing.resolve_artifact_names
- def test_delete_with_eager_relations(self):
+ def test_delete_with_eager_relationships(self):
self.insert_documents()
sess = create_session(bind=testing.db, autocommit=False)
from sqlalchemy.test import testing
from sqlalchemy import Integer, String, ForeignKey, MetaData, and_
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, backref, create_session, compile_mappers, clear_mappers, sessionmaker
+from sqlalchemy.orm import mapper, relationship, relation, \
+ backref, create_session, compile_mappers, clear_mappers, sessionmaker
from sqlalchemy.test.testing import eq_, startswith_
from test.orm import _base, _fixtures
-class RelationTest(_base.MappedTest):
+class RelationshipTest(_base.MappedTest):
"""An extended topological sort test
This is essentially an extension of the "dependency.py" topological sort
@testing.resolve_artifact_names
def setup_mappers(cls):
mapper(A, tbl_a, properties=dict(
- c_rows=relation(C, cascade="all, delete-orphan", backref="a_row")))
+ c_rows=relationship(C, cascade="all, delete-orphan", backref="a_row")))
mapper(B, tbl_b)
mapper(C, tbl_c, properties=dict(
- d_rows=relation(D, cascade="all, delete-orphan", backref="c_row")))
+ d_rows=relationship(D, cascade="all, delete-orphan", backref="c_row")))
mapper(D, tbl_d, properties=dict(
- b_row=relation(B)))
+ b_row=relationship(B)))
@classmethod
@testing.resolve_artifact_names
session.flush()
-class RelationTest2(_base.MappedTest):
- """The ultimate relation() test:
+class RelationshipTest2(_base.MappedTest):
+ """The ultimate relationship() test:
company employee
---------- ----------
def test_explicit(self):
mapper(Company, company_t)
mapper(Employee, employee_t, properties= {
- 'company':relation(Company, primaryjoin=employee_t.c.company_id==company_t.c.company_id, backref='employees'),
- 'reports_to':relation(Employee, primaryjoin=
+ 'company':relationship(Company, primaryjoin=employee_t.c.company_id==company_t.c.company_id, backref='employees'),
+ 'reports_to':relationship(Employee, primaryjoin=
sa.and_(
employee_t.c.emp_id==employee_t.c.reports_to_id,
employee_t.c.company_id==employee_t.c.company_id
def test_implicit(self):
mapper(Company, company_t)
mapper(Employee, employee_t, properties= {
- 'company':relation(Company, backref='employees'),
- 'reports_to':relation(Employee,
+ 'company':relationship(Company, backref='employees'),
+ 'reports_to':relationship(Employee,
remote_side=[employee_t.c.emp_id, employee_t.c.company_id],
foreign_keys=[employee_t.c.reports_to_id],
backref=backref('employees', foreign_keys=None)
def test_very_implicit(self):
mapper(Company, company_t)
mapper(Employee, employee_t, properties= {
- 'company':relation(Company, backref='employees'),
- 'reports_to':relation(Employee,
+ 'company':relationship(Company, backref='employees'),
+ 'reports_to':relationship(Employee,
remote_side=[employee_t.c.emp_id, employee_t.c.company_id],
backref='employees'
)
def test_very_explicit(self):
mapper(Company, company_t)
mapper(Employee, employee_t, properties= {
- 'company':relation(Company, backref='employees'),
- 'reports_to':relation(Employee,
+ 'company':relationship(Company, backref='employees'),
+ 'reports_to':relationship(Employee,
_local_remote_pairs = [
(employee_t.c.reports_to_id, employee_t.c.emp_id),
(employee_t.c.company_id, employee_t.c.company_id)
assert sess.query(Employee).get([c1.company_id, 3]).reports_to.name == 'emp1'
assert sess.query(Employee).get([c2.company_id, 3]).reports_to.name == 'emp5'
-class RelationTest3(_base.MappedTest):
+class RelationshipTest3(_base.MappedTest):
@classmethod
def define_tables(cls, metadata):
Table("jobs", metadata,
mapper(Job, jobs)
mapper(PageVersion, pageversions)
mapper(Page, pages, properties={
- 'job': relation(
+ 'job': relationship(
Job,
backref=backref('pages',
cascade="all, delete-orphan",
order_by=pages.c.pagename)),
- 'currentversion': relation(
+ 'currentversion': relationship(
PageVersion,
uselist=False,
primaryjoin=sa.and_(
pages.c.pagename==pageversions.c.pagename,
pages.c.current_version==pageversions.c.version),
post_update=True),
- 'versions': relation(
+ 'versions': relationship(
PageVersion,
cascade="all, delete-orphan",
primaryjoin=sa.and_(pages.c.jobno==pageversions.c.jobno,
backref=backref('page',lazy=False)
)})
mapper(PageComment, pagecomments, properties={
- 'page': relation(
+ 'page': relationship(
Page,
primaryjoin=sa.and_(pages.c.jobno==pagecomments.c.jobno,
pages.c.pagename==pagecomments.c.pagename),
s.delete(j)
s.flush()
-class RelationTest4(_base.MappedTest):
+class RelationshipTest4(_base.MappedTest):
"""Syncrules on foreign keys that are also primary"""
@classmethod
"""test that active history is enabled on a one-to-many/one that has use_get==True"""
mapper(A, tableA, properties={
- 'b':relation(B, cascade="all,delete-orphan", uselist=False)})
+ 'b':relationship(B, cascade="all,delete-orphan", uselist=False)})
mapper(B, tableB)
compile_mappers()
def test_no_delete_PK_AtoB(self):
"""A cant be deleted without B because B would have no PK value."""
mapper(A, tableA, properties={
- 'bs':relation(B, cascade="save-update")})
+ 'bs':relationship(B, cascade="save-update")})
mapper(B, tableB)
a1 = A()
@testing.resolve_artifact_names
def test_no_delete_PK_BtoA(self):
mapper(B, tableB, properties={
- 'a':relation(A, cascade="save-update")})
+ 'a':relationship(A, cascade="save-update")})
mapper(A, tableA)
b1 = B()
class C(_base.Entity):
pass
mapper(C, tableC, properties={
- 'a':relation(A, cascade="save-update")
+ 'a':relationship(A, cascade="save-update")
})
mapper(A, tableA)
#"save-update, delete-orphan",
"save-update, delete, delete-orphan"):
mapper(B, tableB, properties={
- 'a':relation(A, cascade=cascade, single_parent=True)
+ 'a':relationship(A, cascade=cascade, single_parent=True)
})
mapper(A, tableA)
#"save-update, delete-orphan",
"save-update, delete, delete-orphan"):
mapper(A, tableA, properties={
- 'bs':relation(B, cascade=cascade)
+ 'bs':relationship(B, cascade=cascade)
})
mapper(B, tableB)
@testing.resolve_artifact_names
def test_delete_manual_AtoB(self):
mapper(A, tableA, properties={
- 'bs':relation(B, cascade="none")})
+ 'bs':relationship(B, cascade="none")})
mapper(B, tableB)
a1 = A()
@testing.resolve_artifact_names
def test_delete_manual_BtoA(self):
mapper(B, tableB, properties={
- 'a':relation(A, cascade="none")})
+ 'a':relationship(A, cascade="none")})
mapper(A, tableA)
b1 = B()
assert a1 not in sess
assert b1 not in sess
-class RelationToUniqueTest(_base.MappedTest):
- """test a relation based on a primary join against a unique non-pk column"""
+class RelationshipToUniqueTest(_base.MappedTest):
+ """test a relationship based on a primary join against a unique non-pk column"""
@classmethod
def define_tables(cls, metadata):
@testing.resolve_artifact_names
def test_switch_parent(self):
mapper(A, table_a)
- mapper(B, table_b, properties={"a": relation(A, backref="bs")})
+ mapper(B, table_b, properties={"a": relationship(A, backref="bs")})
session = create_session()
a1, a2 = A(ident="uuid1"), A(ident="uuid2")
session.delete(a1)
session.flush()
-class RelationTest5(_base.MappedTest):
+class RelationshipTest5(_base.MappedTest):
"""Test a map to a select that relates to a map to the table."""
@classmethod
container_select,
order_by=sa.asc(container_select.c.type),
properties=dict(
- lineItems=relation(LineItem,
+ lineItems=relationship(LineItem,
lazy=True,
cascade='all, delete-orphan',
order_by=sa.asc(items.c.id),
for old, new in zip(con.lineItems, newcon.lineItems):
eq_(old.id, new.id)
-class RelationTest6(_base.MappedTest):
- """test a relation with a non-column entity in the primary join,
+class RelationshipTest6(_base.MappedTest):
+ """test a relationship with a non-column entity in the primary join,
is not viewonly, and also has the non-column's clause mentioned in the
foreign keys list.
pass
mapper(Tag, tags, properties={
- 'foo':relation(TagInstance,
+ 'foo':relationship(TagInstance,
primaryjoin=sa.and_(tag_foo.c.data=='iplc_case',
tag_foo.c.tagid==tags.c.id),
foreign_keys=[tag_foo.c.tagid, tag_foo.c.data],
sess.flush()
sess.expunge_all()
- # relation works
+ # relationship works
eq_(sess.query(Tag).all(), [Tag(data='some tag', foo=[TagInstance(data='iplc_case')])])
# both TagInstances were persisted
def test_backref(self):
mapper(User, users, properties={
- 'addresses':relation(Address,
+ 'addresses':relationship(Address,
primaryjoin=addresses.c.user_id==users.c.id,
foreign_keys=addresses.c.user_id,
backref='user')
mapper(Subscriber, subscriber_and_address, properties={
'id':[subscriber.c.id, address.c.subscriber_id],
- 'addresses' : relation(Address,
+ 'addresses' : relationship(Address,
backref=backref("customer"))
})
class ManualBackrefTest(_fixtures.FixtureTest):
- """Test explicit relations that are backrefs to each other."""
+ """Test explicit relationships that are backrefs to each other."""
run_inserts = None
@testing.resolve_artifact_names
def test_o2m(self):
mapper(User, users, properties={
- 'addresses':relation(Address, back_populates='user')
+ 'addresses':relationship(Address, back_populates='user')
})
mapper(Address, addresses, properties={
- 'user':relation(User, back_populates='addresses')
+ 'user':relationship(User, back_populates='addresses')
})
sess = create_session()
@testing.resolve_artifact_names
def test_invalid_key(self):
mapper(User, users, properties={
- 'addresses':relation(Address, back_populates='userr')
+ 'addresses':relationship(Address, back_populates='userr')
})
mapper(Address, addresses, properties={
- 'user':relation(User, back_populates='addresses')
+ 'user':relationship(User, back_populates='addresses')
})
assert_raises(sa.exc.InvalidRequestError, compile_mappers)
@testing.resolve_artifact_names
def test_invalid_target(self):
mapper(User, users, properties={
- 'addresses':relation(Address, back_populates='dingaling'),
+ 'addresses':relationship(Address, back_populates='dingaling'),
})
mapper(Dingaling, dingalings)
mapper(Address, addresses, properties={
- 'dingaling':relation(Dingaling)
+ 'dingaling':relationship(Dingaling)
})
assert_raises_message(sa.exc.ArgumentError,
- r"reverse_property 'dingaling' on relation User.addresses references "
- "relation Address.dingaling, which does not reference mapper Mapper\|User\|users",
+ r"reverse_property 'dingaling' on relationship User.addresses references "
+ "relationship Address.dingaling, which does not reference mapper Mapper\|User\|users",
compile_mappers)
class JoinConditionErrorTest(testing.TestBase):
__tablename__ = 'c2'
id = Column('id', Integer, primary_key=True)
c1id = Column('c1id', Integer, ForeignKey('c1.id'))
- c2 = relation(C1, primaryjoin=C1.id)
+ c2 = relationship(C1, primaryjoin=C1.id)
assert_raises(sa.exc.ArgumentError, compile_mappers)
__tablename__ = 'c2'
id = Column('id', Integer, primary_key=True)
c1id = Column('c1id', Integer, ForeignKey('c1.id'))
- c2 = relation(C1, primaryjoin="x"=="y")
+ c2 = relationship(C1, primaryjoin="x"=="y")
assert_raises(sa.exc.ArgumentError, compile_mappers)
class C2(object):
pass
- mapper(C1, t1, properties={'c2':relation(C2, primaryjoin=t1.join(t2))})
+ mapper(C1, t1, properties={'c2':relationship(C2, primaryjoin=t1.join(t2))})
mapper(C2, t2)
assert_raises(sa.exc.ArgumentError, compile_mappers)
class C2(object):
pass
- mapper(C1, t1, properties={'c2':relation(C2)})
+ mapper(C1, t1, properties={'c2':relationship(C2)})
mapper(C2, t3)
assert_raises(sa.exc.NoReferencedColumnError, compile_mappers)
class C2(object):
pass
- mapper(C1, t1, properties={'c2':relation(C2)})
+ mapper(C1, t1, properties={'c2':relationship(C2)})
mapper(C2, t3)
assert_raises(sa.exc.ArgumentError, compile_mappers)
clear_mappers()
class TypeMatchTest(_base.MappedTest):
- """test errors raised when trying to add items whose type is not handled by a relation"""
+ """test errors raised when trying to add items whose type is not handled by a relationship"""
@classmethod
def define_tables(cls, metadata):
class A(_base.Entity): pass
class B(_base.Entity): pass
class C(_base.Entity): pass
- mapper(A, a, properties={'bs':relation(B)})
+ mapper(A, a, properties={'bs':relationship(B)})
mapper(B, b)
mapper(C, c)
class A(_base.Entity): pass
class B(_base.Entity): pass
class C(_base.Entity): pass
- mapper(A, a, properties={'bs':relation(B, cascade="none")})
+ mapper(A, a, properties={'bs':relationship(B, cascade="none")})
mapper(B, b)
mapper(C, c)
class A(_base.Entity): pass
class B(_base.Entity): pass
class C(B): pass
- mapper(A, a, properties={'bs':relation(B, cascade="none")})
+ mapper(A, a, properties={'bs':relationship(B, cascade="none")})
mapper(B, b)
mapper(C, c, inherits=B)
class D(_base.Entity): pass
mapper(A, a)
mapper(B, b, inherits=A)
- mapper(D, d, properties={"a":relation(A, cascade="none")})
+ mapper(D, d, properties={"a":relationship(A, cascade="none")})
b1 = B()
d1 = D()
d1.a = b1
class D(_base.Entity): pass
mapper(A, a)
mapper(B, b)
- mapper(D, d, properties={"a":relation(A)})
+ mapper(D, d, properties={"a":relationship(A)})
b1 = B()
d1 = D()
d1.a = b1
class T2(_base.Entity): pass
mapper(T2, t2)
mapper(T1, t1, properties={
- 't2s':relation(T2, secondary=t3, backref='t1s')})
+ 't2s':relationship(T2, secondary=t3, backref='t1s')})
a = T1()
a.col1 = "aid"
class B(_base.ComparableEntity):pass
mapper(A, t1, properties={
- 'bs':relation(B, secondary=t1t2, backref=backref('as_', viewonly=True))
+ 'bs':relationship(B, secondary=t1t2, backref=backref('as_', viewonly=True))
})
mapper(B, t2)
class C3(_base.Entity): pass
mapper(C1, t1, properties={
- 't2s':relation(C2),
- 't2_view':relation(C2,
+ 't2s':relationship(C2),
+ 't2_view':relationship(C2,
viewonly=True,
primaryjoin=sa.and_(t1.c.id==t2.c.t1id,
t3.c.t2id==t2.c.id,
t3.c.data==t1.c.data))})
mapper(C2, t2)
mapper(C3, t3, properties={
- 't2':relation(C2)})
+ 't2':relationship(C2)})
c1 = C1()
c1.data = 'c1data'
class C3(_base.Entity): pass
mapper(C1, t1, properties={
- 't2s':relation(C2),
- 't2_view':relation(C2,
+ 't2s':relationship(C2),
+ 't2_view':relationship(C2,
viewonly=True,
primaryjoin=sa.and_(t1.c.t1id==t2.c.t1id_ref,
t3.c.t2id_ref==t2.c.t2id,
t3.c.data==t1.c.data))})
mapper(C2, t2)
mapper(C3, t3, properties={
- 't2':relation(C2)})
+ 't2':relationship(C2)})
c1 = C1()
c1.data = 'c1data'
class B(object): pass
mapper( B, t2, )
m = mapper( A, t1, properties=dict(
- b_view = relation( B, secondary=t12, viewonly=True),
- b_plain= relation( B, secondary=t12),
+ b_view = relationship( B, secondary=t12, viewonly=True),
+ b_plain= relationship( B, secondary=t12),
)
)
compile_mappers()
pass
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=foos.c.id > bars.c.fid,
foreign_keys=[bars.c.fid],
viewonly=True)})
Column('data', String(50)))
@testing.resolve_artifact_names
- def test_relation_on_or(self):
+ def test_relationship_on_or(self):
class Foo(_base.ComparableEntity):
pass
class Bar(_base.ComparableEntity):
pass
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=sa.or_(bars.c.id == foos.c.bid1,
bars.c.id == foos.c.bid2),
uselist=True,
Column('data', String(50)))
@testing.resolve_artifact_names
- def test_relation_on_or(self):
+ def test_relationship_on_or(self):
class Foo(_base.ComparableEntity):
pass
class Bar(_base.ComparableEntity):
pass
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=sa.or_(bars.c.fid1 == foos.c.id,
bars.c.fid2 == foos.c.id),
viewonly=True)})
@testing.resolve_artifact_names
def test_basic(self):
mapper(T1, t1, properties={
- 't3s':relation(T3, primaryjoin=sa.and_(
+ 't3s':relationship(T3, primaryjoin=sa.and_(
t1.c.id==t2.c.t1id,
t2.c.id==t2tot3.c.t2id,
t3.c.id==t2tot3.c.t3id),
foreign_keys=t3.c.id, remote_side=t2.c.t1id)
})
mapper(T2, t2, properties={
- 't1':relation(T1),
- 't3s':relation(T3, secondary=t2tot3)
+ 't1':relationship(T1),
+ 't3s':relationship(T3, secondary=t2tot3)
})
mapper(T3, t3)
@testing.resolve_artifact_names
def test_remote_side_escalation(self):
mapper(T1, t1, properties={
- 't3s':relation(T3,
+ 't3s':relationship(T3,
primaryjoin=sa.and_(t1.c.id==t2.c.t1id,
t2.c.id==t2tot3.c.t2id,
t3.c.id==t2tot3.c.t3id
viewonly=True,
foreign_keys=t3.c.id)})
mapper(T2, t2, properties={
- 't1':relation(T1),
- 't3s':relation(T3, secondary=t2tot3)})
+ 't1':relationship(T1),
+ 't3s':relationship(T3, secondary=t2tot3)})
mapper(T3, t3)
assert_raises_message(sa.exc.ArgumentError,
"Specify remote_side argument",
# use a function within join condition. but specifying
# local_remote_pairs overrides all parsing of the join condition.
mapper(T1, t1, properties={
- 't2s':relation(T2,
+ 't2s':relationship(T2,
primaryjoin=t1.c.id==sa.func.lower(t2.c.t1id),
_local_remote_pairs=[(t1.c.id, t2.c.t1id)],
foreign_keys=[t2.c.t1id])})
def test_manytoone_funcfk(self):
mapper(T1, t1)
mapper(T2, t2, properties={
- 't1':relation(T1,
+ 't1':relationship(T1,
primaryjoin=t1.c.id==sa.func.lower(t2.c.t1id),
_local_remote_pairs=[(t2.c.t1id, t1.c.id)],
foreign_keys=[t2.c.t1id],
@testing.resolve_artifact_names
def test_onetomany_func_referent(self):
mapper(T1, t1, properties={
- 't2s':relation(T2,
+ 't2s':relationship(T2,
primaryjoin=sa.func.lower(t1.c.id)==t2.c.t1id,
_local_remote_pairs=[(t1.c.id, t2.c.t1id)],
foreign_keys=[t2.c.t1id])})
def test_manytoone_func_referent(self):
mapper(T1, t1)
mapper(T2, t2, properties={
- 't1':relation(T1,
+ 't1':relationship(T1,
primaryjoin=sa.func.lower(t1.c.id)==t2.c.t1id,
_local_remote_pairs=[(t2.c.t1id, t1.c.id)],
foreign_keys=[t2.c.t1id], uselist=True)})
@testing.resolve_artifact_names
def test_escalation_1(self):
mapper(T1, t1, properties={
- 't2s':relation(T2,
+ 't2s':relationship(T2,
primaryjoin=t1.c.id==sa.func.lower(t2.c.t1id),
_local_remote_pairs=[(t1.c.id, t2.c.t1id)],
foreign_keys=[t2.c.t1id],
@testing.resolve_artifact_names
def test_escalation_2(self):
mapper(T1, t1, properties={
- 't2s':relation(T2,
+ 't2s':relationship(T2,
primaryjoin=t1.c.id==sa.func.lower(t2.c.t1id),
_local_remote_pairs=[(t1.c.id, t2.c.t1id)])})
mapper(T2, t2)
@testing.resolve_artifact_names
def test_o2m_backref(self):
mapper(T1, t1, properties={
- 't1s':relation(T1, backref='parent')
+ 't1s':relationship(T1, backref='parent')
})
assert_raises_message(sa.exc.ArgumentError, "T1.t1s and back-reference T1.parent are "
@testing.resolve_artifact_names
def test_m2o_backref(self):
mapper(T1, t1, properties={
- 't1s':relation(T1, backref=backref('parent', remote_side=t1.c.id), remote_side=t1.c.id)
+ 't1s':relationship(T1, backref=backref('parent', remote_side=t1.c.id), remote_side=t1.c.id)
})
assert_raises_message(sa.exc.ArgumentError, "T1.t1s and back-reference T1.parent are "
@testing.resolve_artifact_names
def test_o2m_explicit(self):
mapper(T1, t1, properties={
- 't1s':relation(T1, back_populates='parent'),
- 'parent':relation(T1, back_populates='t1s'),
+ 't1s':relationship(T1, back_populates='parent'),
+ 'parent':relationship(T1, back_populates='t1s'),
})
# can't be sure of ordering here
@testing.resolve_artifact_names
def test_m2o_explicit(self):
mapper(T1, t1, properties={
- 't1s':relation(T1, back_populates='parent', remote_side=t1.c.id),
- 'parent':relation(T1, back_populates='t1s', remote_side=t1.c.id)
+ 't1s':relationship(T1, back_populates='parent', remote_side=t1.c.id),
+ 'parent':relationship(T1, back_populates='t1s', remote_side=t1.c.id)
})
# can't be sure of ordering here
"mean to set remote_side on the many-to-one side ?", sa.orm.compile_mappers)
-class InvalidRelationEscalationTest(_base.MappedTest):
+class InvalidRelationshipEscalationTest(_base.MappedTest):
@classmethod
def define_tables(cls, metadata):
@testing.resolve_artifact_names
def test_no_join(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar)})
+ 'bars':relationship(Bar)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
"Could not determine join condition between parent/child "
- "tables on relation", sa.orm.compile_mappers)
+ "tables on relationship", sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_no_join_self_ref(self):
mapper(Foo, foos, properties={
- 'foos':relation(Foo)})
+ 'foos':relationship(Foo)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
"Could not determine join condition between parent/child "
- "tables on relation", sa.orm.compile_mappers)
+ "tables on relationship", sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_no_equated(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=foos.c.id>bars.c.fid)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
- "Could not determine relation direction for primaryjoin condition",
+ "Could not determine relationship direction for primaryjoin condition",
sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_no_equated_fks(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=foos.c.id>bars.c.fid,
foreign_keys=bars.c.fid)})
mapper(Bar, bars)
@testing.resolve_artifact_names
def test_ambiguous_fks(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=foos.c.id==bars.c.fid,
foreign_keys=[foos.c.id, bars.c.fid])})
mapper(Bar, bars)
@testing.resolve_artifact_names
def test_ambiguous_remoteside_o2m(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=foos.c.id==bars.c.fid,
foreign_keys=[bars.c.fid],
remote_side=[foos.c.id, bars.c.fid],
@testing.resolve_artifact_names
def test_ambiguous_remoteside_m2o(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=foos.c.id==bars.c.fid,
foreign_keys=[foos.c.id],
remote_side=[foos.c.id, bars.c.fid],
@testing.resolve_artifact_names
def test_no_equated_self_ref(self):
mapper(Foo, foos, properties={
- 'foos':relation(Foo,
+ 'foos':relationship(Foo,
primaryjoin=foos.c.id>foos.c.fid)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
- "Could not determine relation direction for primaryjoin condition",
+ "Could not determine relationship direction for primaryjoin condition",
sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_no_equated_self_ref(self):
mapper(Foo, foos, properties={
- 'foos':relation(Foo,
+ 'foos':relationship(Foo,
primaryjoin=foos.c.id>foos.c.fid,
foreign_keys=[foos.c.fid])})
mapper(Bar, bars)
@testing.resolve_artifact_names
def test_no_equated_viewonly(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=foos.c.id>bars.c.fid,
viewonly=True)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
- "Could not determine relation direction for primaryjoin condition",
+ "Could not determine relationship direction for primaryjoin condition",
sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_no_equated_self_ref_viewonly(self):
mapper(Foo, foos, properties={
- 'foos':relation(Foo,
+ 'foos':relationship(Foo,
primaryjoin=foos.c.id>foos.c.fid,
viewonly=True)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
"Specify the 'foreign_keys' argument to indicate which columns "
- "on the relation are foreign.", sa.orm.compile_mappers)
+ "on the relationship are foreign.", sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_no_equated_self_ref_viewonly_fks(self):
mapper(Foo, foos, properties={
- 'foos':relation(Foo,
+ 'foos':relationship(Foo,
primaryjoin=foos.c.id>foos.c.fid,
viewonly=True,
foreign_keys=[foos.c.fid])})
@testing.resolve_artifact_names
def test_equated(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
primaryjoin=foos.c.id==bars.c.fid)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
- "Could not determine relation direction for primaryjoin condition",
+ "Could not determine relationship direction for primaryjoin condition",
sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_equated_self_ref(self):
mapper(Foo, foos, properties={
- 'foos':relation(Foo,
+ 'foos':relationship(Foo,
primaryjoin=foos.c.id==foos.c.fid)})
assert_raises_message(
sa.exc.ArgumentError,
- "Could not determine relation direction for primaryjoin condition",
+ "Could not determine relationship direction for primaryjoin condition",
sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_equated_self_ref_wrong_fks(self):
mapper(Foo, foos, properties={
- 'foos':relation(Foo,
+ 'foos':relationship(Foo,
primaryjoin=foos.c.id==foos.c.fid,
foreign_keys=[bars.c.id])})
assert_raises_message(
sa.exc.ArgumentError,
- "Could not determine relation direction for primaryjoin condition",
+ "Could not determine relationship direction for primaryjoin condition",
sa.orm.compile_mappers)
-class InvalidRelationEscalationTestM2M(_base.MappedTest):
+class InvalidRelationshipEscalationTestM2M(_base.MappedTest):
@classmethod
def define_tables(cls, metadata):
@testing.resolve_artifact_names
def test_no_join(self):
mapper(Foo, foos, properties={
- 'bars': relation(Bar, secondary=foobars)})
+ 'bars': relationship(Bar, secondary=foobars)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
"Could not determine join condition between parent/child tables "
- "on relation", sa.orm.compile_mappers)
+ "on relationship", sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_no_secondaryjoin(self):
mapper(Foo, foos, properties={
- 'bars': relation(Bar,
+ 'bars': relationship(Bar,
secondary=foobars,
primaryjoin=foos.c.id > foobars.c.fid)})
mapper(Bar, bars)
assert_raises_message(
sa.exc.ArgumentError,
"Could not determine join condition between parent/child tables "
- "on relation",
+ "on relationship",
sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_bad_primaryjoin(self):
mapper(Foo, foos, properties={
- 'bars': relation(Bar,
+ 'bars': relationship(Bar,
secondary=foobars,
primaryjoin=foos.c.id > foobars.c.fid,
secondaryjoin=foobars.c.bid<=bars.c.id)})
assert_raises_message(
sa.exc.ArgumentError,
- "Could not determine relation direction for primaryjoin condition",
+ "Could not determine relationship direction for primaryjoin condition",
sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_bad_secondaryjoin(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
secondary=foobars,
primaryjoin=foos.c.id == foobars.c.fid,
secondaryjoin=foobars.c.bid <= bars.c.id,
assert_raises_message(
sa.exc.ArgumentError,
- "Could not determine relation direction for secondaryjoin "
+ "Could not determine relationship direction for secondaryjoin "
"condition", sa.orm.compile_mappers)
@testing.resolve_artifact_names
def test_no_equated_secondaryjoin(self):
mapper(Foo, foos, properties={
- 'bars':relation(Bar,
+ 'bars':relationship(Bar,
secondary=foobars,
primaryjoin=foos.c.id == foobars.c.fid,
secondaryjoin=foobars.c.bid <= bars.c.id,
"secondaryjoin condition", sa.orm.compile_mappers)
+class RelationDeprecationTest(_base.MappedTest):
+ run_inserts = 'once'
+ run_deletes = None
+
+ @classmethod
+ def define_tables(cls, metadata):
+ Table('users_table', metadata,
+ Column('id', Integer, primary_key=True),
+ Column('name', String(64)))
+
+ Table('addresses_table', metadata,
+ Column('id', Integer, primary_key=True),
+ Column('user_id', Integer, ForeignKey('users_table.id')),
+ Column('email_address', String(128)),
+ Column('purpose', String(16)),
+ Column('bounces', Integer, default=0))
+
+ @classmethod
+ def setup_classes(cls):
+ class User(_base.BasicEntity):
+ pass
+
+ class Address(_base.BasicEntity):
+ pass
+
+ @classmethod
+ def fixtures(cls):
+ return dict(
+ users_table=(
+ ('id', 'name'),
+ (1, 'jack'),
+ (2, 'ed'),
+ (3, 'fred'),
+ (4, 'chuck')),
+
+ addresses_table=(
+ ('id', 'user_id', 'email_address', 'purpose', 'bounces'),
+ (1, 1, 'jack@jack.home', 'Personal', 0),
+ (2, 1, 'jack@jack.bizz', 'Work', 1),
+ (3, 2, 'ed@foo.bar', 'Personal', 0),
+ (4, 3, 'fred@the.fred', 'Personal', 10)))
+
+ @testing.resolve_artifact_names
+ def test_relation(self):
+ mapper(User, users_table, properties=dict(
+ addresses=relation(Address, backref='user'),
+ ))
+ mapper(Address, addresses_table)
+
+ session = create_session()
+
+ ed = session.query(User).filter(User.addresses.any(
+ Address.email_address == 'ed@foo.bar')).one()
+
+
+
from sqlalchemy.orm import scoped_session
from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, query
+from sqlalchemy.orm import mapper, relationship, query
from sqlalchemy.test.testing import eq_
from test.orm import _base
custom_query = Session.query_property(query_cls=CustomQuery)
mapper(SomeObject, table1, properties={
- 'options':relation(SomeOtherObject)})
+ 'options':relationship(SomeOtherObject)})
mapper(SomeOtherObject, table2)
s = SomeObject(id=1, data="hello")
def setup_mappers(cls):
Session = scoped_session(sa.orm.create_session)
Session.mapper(SomeObject, table1, properties={
- 'options':relation(SomeOtherObject)
+ 'options':relationship(SomeOtherObject)
})
Session.mapper(SomeOtherObject, table2)
from sqlalchemy.test import engines, testing, config
from sqlalchemy import Integer, String, Sequence
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, backref, eagerload
+from sqlalchemy.orm import mapper, relationship, backref, eagerload
from sqlalchemy.test.testing import eq_
from test.engine import _base as engine_base
from test.orm import _base, _fixtures
def test_expunge_cascade(self):
mapper(Address, addresses)
mapper(User, users, properties={
- 'addresses':relation(Address,
+ 'addresses':relationship(Address,
backref=backref("user", cascade="all"),
cascade="all")})
mapper(Address, addresses_unbound)
mapper(User, users_unbound, properties={
- 'addresses':relation(Address,
+ 'addresses':relationship(Address,
backref=backref("user", cascade="all"),
cascade="all")})
mapper(Address, addresses_unbound)
mapper(User, users_unbound, properties={
- 'addresses':relation(Address,
+ 'addresses':relationship(Address,
backref=backref("user", cascade="all"),
cascade="all")})
"""
mapper(User, users, properties={
- 'addresses':relation(Address, backref="user")})
+ 'addresses':relationship(Address, backref="user")})
mapper(Address, addresses)
sess = create_session(autoflush=True, autocommit=False)
def test_autoflush_rollback(self):
mapper(Address, addresses)
mapper(User, users, properties={
- 'addresses':relation(Address)})
+ 'addresses':relationship(Address)})
_fixtures.run_inserts_for(users)
_fixtures.run_inserts_for(addresses)
s = create_session()
mapper(User, users, properties={
- 'addresses':relation(Address, cascade="all, delete")
+ 'addresses':relationship(Address, cascade="all, delete")
})
mapper(Address, addresses)
def test_is_modified(self):
s = create_session()
- mapper(User, users, properties={'addresses':relation(Address)})
+ mapper(User, users, properties={'addresses':relationship(Address)})
mapper(Address, addresses)
# save user
def test_weakref_with_cycles_o2m(self):
s = sessionmaker()()
mapper(User, users, properties={
- "addresses":relation(Address, backref="user")
+ "addresses":relationship(Address, backref="user")
})
mapper(Address, addresses)
s.add(User(name="ed", addresses=[Address(email_address="ed1")]))
def test_weakref_with_cycles_o2o(self):
s = sessionmaker()()
mapper(User, users, properties={
- "address":relation(Address, backref="user", uselist=False)
+ "address":relationship(Address, backref="user", uselist=False)
})
mapper(Address, addresses)
s.add(User(name="ed", address=Address(email_address="ed1")))
def test_no_save_cascade_1(self):
mapper(Address, addresses)
mapper(User, users, properties=dict(
- addresses=relation(Address, cascade="none", backref="user")))
+ addresses=relationship(Address, cascade="none", backref="user")))
s = create_session()
u = User(name='u1')
def test_no_save_cascade_2(self):
mapper(Address, addresses)
mapper(User, users, properties=dict(
- addresses=relation(Address,
+ addresses=relationship(Address,
cascade="all",
backref=backref("user", cascade="none"))))
@classmethod
def setup_mappers(cls):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user',
+ 'addresses':relationship(Address, backref='user',
cascade="all, delete-orphan", order_by=addresses.c.id),
})
mapper(Address, addresses)
from sqlalchemy import Integer, String, ForeignKey, literal_column
from sqlalchemy.test.schema import Table
from sqlalchemy.test.schema import Column
-from sqlalchemy.orm import mapper, relation, create_session, column_property
+from sqlalchemy.orm import mapper, relationship, create_session, column_property
from sqlalchemy.test.testing import eq_, ne_
from test.orm import _base, _fixtures
from test.engine import _base as engine_base
def test_backref(self):
am = mapper(Address, addresses)
m = mapper(User, users, properties=dict(
- addresses = relation(am, backref='user', lazy=False)))
+ addresses = relationship(am, backref='user', lazy=False)))
session = create_session(autocommit=False)
self.assert_(t1.txt == txt)
@testing.resolve_artifact_names
- def test_relation(self):
+ def test_relationship(self):
mapper(Test, uni_t1, properties={
- 't2s': relation(Test2)})
+ 't2s': relationship(Test2)})
mapper(Test2, uni_t2)
txt = u"\u0160\u0110\u0106\u010c\u017d"
pass
mapper(A, t1, properties={
- 't2s':relation(B)})
+ 't2s':relationship(B)})
mapper(B, t2)
a1 = A()
def test_basic(self):
m1 = mapper(PersonSite, peoplesites)
m2 = mapper(Person, people, properties={
- 'sites' : relation(PersonSite)})
+ 'sites' : relationship(PersonSite)})
sa.orm.compile_mappers()
eq_(list(m2.get_property('sites').synchronize_pairs),
def test_basic(self):
mapper(MyOtherClass, myothertable)
mapper(MyClass, mytable, properties={
- 'children':relation(MyOtherClass,
+ 'children':relationship(MyOtherClass,
passive_deletes=True,
cascade="all")})
session = create_session()
# the unusual scenario where a trigger or something might be deleting
# a many-to-one on deletion of the parent row
mapper(MyOtherClass, myothertable, properties={
- 'myclass':relation(MyClass, cascade="all, delete", passive_deletes=True)
+ 'myclass':relationship(MyClass, cascade="all, delete", passive_deletes=True)
})
mapper(MyClass, mytable)
mapper(MyOtherClass, myothertable)
try:
mapper(MyClass, mytable, properties={
- 'children':relation(MyOtherClass,
+ 'children':relationship(MyOtherClass,
passive_deletes='all',
cascade="all")})
assert False
def test_extra_passive(self):
mapper(MyOtherClass, myothertable)
mapper(MyClass, mytable, properties={
- 'children': relation(MyOtherClass,
+ 'children': relationship(MyOtherClass,
passive_deletes='all',
cascade="save-update")})
def test_extra_passive_2(self):
mapper(MyOtherClass, myothertable)
mapper(MyClass, mytable, properties={
- 'children': relation(MyOtherClass,
+ 'children': relationship(MyOtherClass,
passive_deletes='all',
cascade="save-update")})
@testing.fails_on('firebird', 'Data type unknown on the parameter')
@testing.resolve_artifact_names
- def test_used_in_relation(self):
+ def test_used_in_relationship(self):
"""A server-side default can be used as the target of a foreign key"""
mapper(Hoho, default_t, properties={
- 'secondaries':relation(Secondary, order_by=secondary_table.c.id)})
+ 'secondaries':relationship(Secondary, order_by=secondary_table.c.id)})
mapper(Secondary, secondary_table)
h1 = Hoho()
"""Basic save of one to many."""
m = mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=True)
+ addresses = relationship(mapper(Address, addresses), lazy=True)
))
u = User(name= 'one2manytester')
a = Address(email_address='one2many@test.org')
"""Modifying the child items of an object."""
m = mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=True)))
+ addresses = relationship(mapper(Address, addresses), lazy=True)))
u1 = User(name='user1')
u1.addresses = []
"""
m = mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=True)))
+ addresses = relationship(mapper(Address, addresses), lazy=True)))
u1 = User(name='user1')
u2 = User(name='user2')
@testing.resolve_artifact_names
def test_child_move_2(self):
m = mapper(User, users, properties=dict(
- addresses = relation(mapper(Address, addresses), lazy=True)))
+ addresses = relationship(mapper(Address, addresses), lazy=True)))
u1 = User(name='user1')
u2 = User(name='user2')
@testing.resolve_artifact_names
def test_o2m_delete_parent(self):
m = mapper(User, users, properties=dict(
- address = relation(mapper(Address, addresses),
+ address = relationship(mapper(Address, addresses),
lazy=True,
uselist=False)))
@testing.resolve_artifact_names
def test_one_to_one(self):
m = mapper(User, users, properties=dict(
- address = relation(mapper(Address, addresses),
+ address = relationship(mapper(Address, addresses),
lazy=True,
uselist=False)))
def test_bidirectional(self):
m1 = mapper(User, users)
m2 = mapper(Address, addresses, properties=dict(
- user = relation(m1, lazy=False, backref='addresses')))
+ user = relationship(m1, lazy=False, backref='addresses')))
u = User(name='test')
session.flush()
@testing.resolve_artifact_names
- def test_double_relation(self):
+ def test_double_relationship(self):
m2 = mapper(Address, addresses)
m = mapper(User, users, properties={
- 'boston_addresses' : relation(m2, primaryjoin=
+ 'boston_addresses' : relationship(m2, primaryjoin=
sa.and_(users.c.id==addresses.c.user_id,
addresses.c.email_address.like('%boston%'))),
- 'newyork_addresses' : relation(m2, primaryjoin=
+ 'newyork_addresses' : relationship(m2, primaryjoin=
sa.and_(users.c.id==addresses.c.user_id,
addresses.c.email_address.like('%newyork%')))})
@testing.resolve_artifact_names
def test_lazyattr_commit(self):
- """Lazily loaded relations.
+ """Lazily loaded relationships.
When a lazy-loaded list is unloaded, and a commit occurs, that the
'passive' call on that list does not blow away its value
"""
mapper(User, users, properties = {
- 'addresses': relation(mapper(Address, addresses))})
+ 'addresses': relationship(mapper(Address, addresses))})
u = User(name='u1')
u.addresses.append(Address(email_address='u1@e1'))
def test_history_get(self):
"""The history lazy-fetches data when it wasn't otherwise loaded."""
mapper(User, users, properties={
- 'addresses':relation(Address, cascade="all, delete-orphan")})
+ 'addresses':relationship(Address, cascade="all, delete-orphan")})
mapper(Address, addresses)
u = User(name='u1')
def test_m2o_one_to_one(self):
# TODO: put assertion in here !!!
m = mapper(Address, addresses, properties=dict(
- user = relation(mapper(User, users), lazy=True, uselist=False)))
+ user = relationship(mapper(User, users), lazy=True, uselist=False)))
session = create_session()
@testing.resolve_artifact_names
def test_many_to_one_1(self):
m = mapper(Address, addresses, properties=dict(
- user = relation(mapper(User, users), lazy=True)))
+ user = relationship(mapper(User, users), lazy=True)))
a1 = Address(email_address='emailaddress1')
u1 = User(name='user1')
@testing.resolve_artifact_names
def test_many_to_one_2(self):
m = mapper(Address, addresses, properties=dict(
- user = relation(mapper(User, users), lazy=True)))
+ user = relationship(mapper(User, users), lazy=True)))
a1 = Address(email_address='emailaddress1')
a2 = Address(email_address='emailaddress2')
@testing.resolve_artifact_names
def test_many_to_one_3(self):
m = mapper(Address, addresses, properties=dict(
- user = relation(mapper(User, users), lazy=True)))
+ user = relationship(mapper(User, users), lazy=True)))
a1 = Address(email_address='emailaddress1')
u1 = User(name='user1')
@testing.resolve_artifact_names
def test_bidirectional_no_load(self):
mapper(User, users, properties={
- 'addresses':relation(Address, backref='user', lazy=None)})
+ 'addresses':relationship(Address, backref='user', lazy=None)})
mapper(Address, addresses)
# try it on unsaved objects
mapper(Keyword, keywords)
m = mapper(Item, items, properties=dict(
- keywords=relation(Keyword,
+ keywords=relationship(Keyword,
item_keywords,
lazy=False,
order_by=keywords.c.name)))
"""
mapper(Keyword, keywords)
mapper(Item, items, properties=dict(
- keywords = relation(Keyword, item_keywords, lazy=False),
+ keywords = relationship(Keyword, item_keywords, lazy=False),
))
i = Item(description='i1')
@testing.resolve_artifact_names
def test_scalar(self):
- """sa.dependency won't delete an m2m relation referencing None."""
+ """sa.dependency won't delete an m2m relationship referencing None."""
mapper(Keyword, keywords)
mapper(Item, items, properties=dict(
- keyword=relation(Keyword, secondary=item_keywords, uselist=False)))
+ keyword=relationship(Keyword, secondary=item_keywords, uselist=False)))
i = Item(description='x')
session = create_session()
"""Assorted history operations on a many to many"""
mapper(Keyword, keywords)
mapper(Item, items, properties=dict(
- keywords=relation(Keyword,
+ keywords=relationship(Keyword,
secondary=item_keywords,
lazy=False,
order_by=keywords.c.name)))
mapper(IKAssociation, item_keywords,
primary_key=[item_keywords.c.item_id, item_keywords.c.keyword_id],
properties=dict(
- keyword=relation(mapper(Keyword, keywords, non_primary=True),
+ keyword=relationship(mapper(Keyword, keywords, non_primary=True),
lazy=False,
uselist=False,
order_by=keywords.c.name # note here is a valid place where order_by can be used
- ))) # on a scalar relation(); to determine eager ordering of
+ ))) # on a scalar relationship(); to determine eager ordering of
# the parent object within its collection.
mapper(Item, items, properties=dict(
- keywords=relation(IKAssociation, lazy=False)))
+ keywords=relationship(IKAssociation, lazy=False)))
session = create_session()
def test_m2o_nonmatch(self):
mapper(User, users)
mapper(Address, addresses, properties=dict(
- user = relation(User, lazy=True, uselist=False)))
+ user = relationship(User, lazy=True, uselist=False)))
session = create_session()
mapper(Keyword, keywords)
mapper(Item, items, properties=dict(
- keywords = relation(Keyword, secondary=assoc, lazy=False),))
+ keywords = relationship(Keyword, secondary=assoc, lazy=False),))
i = Item()
k1 = Keyword()
@testing.resolve_artifact_names
def test_onetomany(self):
mapper(T5, t5, properties={
- 't6s':relation(T6, cascade="all, delete-orphan")
+ 't6s':relationship(T6, cascade="all, delete-orphan")
})
mapper(T6, t6)
@testing.resolve_artifact_names
def test_manytomany(self):
mapper(T5, t5, properties={
- 't7s':relation(T7, secondary=t5t7, cascade="all")
+ 't7s':relationship(T7, secondary=t5t7, cascade="all")
})
mapper(T7, t7)
def test_manytoone(self):
mapper(T6, t6, properties={
- 't5':relation(T5)
+ 't5':relationship(T5)
})
mapper(T5, t5)
from sqlalchemy.test import engines, testing
from sqlalchemy import Integer, String, ForeignKey, literal_column, orm
from sqlalchemy.test.schema import Table, Column
-from sqlalchemy.orm import mapper, relation, create_session, column_property, sessionmaker
+from sqlalchemy.orm import mapper, relationship, create_session, column_property, sessionmaker
from sqlalchemy.test.testing import eq_, ne_, assert_raises, assert_raises_message
from test.orm import _base, _fixtures
from test.engine import _base as engine_base
def setup_mappers(cls):
mapper(P, p, version_id_col=p.c.version_id,
properties={
- 'c':relation(C, uselist=False, cascade='all, delete-orphan')
+ 'c':relationship(C, uselist=False, cascade='all, delete-orphan')
})
mapper(C, c, version_id_col=c.c.version_id)
mapper(P, p, version_id_col=p.c.version_id,
version_id_generator=lambda x:make_uuid(),
properties={
- 'c':relation(C, uselist=False, cascade='all, delete-orphan')
+ 'c':relationship(C, uselist=False, cascade='all, delete-orphan')
})
mapper(C, c, version_id_col=c.c.version_id,
version_id_generator=lambda x:make_uuid(),
valueMapper = mapper(Value, values)
attrMapper = mapper(Attribute, attributes, properties=dict(
- values=relation(valueMapper, cascade="save-update", backref="attribute")
+ values=relationship(valueMapper, cascade="save-update", backref="attribute")
))
itemMapper = mapper(Item, items, properties=dict(
- attributes=relation(attrMapper, cascade="save-update", backref="item")
+ attributes=relationship(attrMapper, cascade="save-update", backref="item")
))
orderMapper = mapper(Order, orders, properties=dict(
- items=relation(itemMapper, cascade="save-update", backref="order")
+ items=relationship(itemMapper, cascade="save-update", backref="order")
))
class Item(object):pass
class SubItem(object):pass
-mapper(Item, items, properties={'subs':relation(SubItem, lazy=False)})
+mapper(Item, items, properties={'subs':relationship(SubItem, lazy=False)})
mapper(SubItem, subitems)
def load():
use_backref = True
if use_backref:
- class_mapper(T1).add_property( 't2s', relation(T2, backref=backref("t1", cascade=cascade), cascade=cascade))
- class_mapper(T2).add_property ( 't3s', relation(T3, backref=backref("t2",cascade=cascade), cascade=cascade) )
- class_mapper(T3).add_property( 't4s', relation(T4, backref=backref("t3", cascade=cascade), cascade=cascade) )
+ class_mapper(T1).add_property( 't2s', relationship(T2, backref=backref("t1", cascade=cascade), cascade=cascade))
+ class_mapper(T2).add_property ( 't3s', relationship(T3, backref=backref("t2",cascade=cascade), cascade=cascade) )
+ class_mapper(T3).add_property( 't4s', relationship(T4, backref=backref("t3", cascade=cascade), cascade=cascade) )
else:
- T1.mapper.add_property( 't2s', relation(T2, cascade=cascade))
- T2.mapper.add_property ( 't3s', relation(T3, cascade=cascade) )
- T3.mapper.add_property( 't4s', relation(T4, cascade=cascade) )
+ T1.mapper.add_property( 't2s', relationship(T2, cascade=cascade))
+ T2.mapper.add_property ( 't3s', relationship(T3, cascade=cascade) )
+ T3.mapper.add_property( 't4s', relationship(T4, cascade=cascade) )
now = time.time()
print "start"
getattr(self, 'address', None))
mapper(Person, Person_table, properties={
- 'emails': relation(Email, backref='owner', lazy=False)
+ 'emails': relationship(Email, backref='owner', lazy=False)
})
mapper(Email, Email_table)
compile_mappers()
@profiled('mapper')
def setup_mappers():
mapper(Item, items, properties={
- 'subitems': relation(SubItem, backref='item', lazy=True)
+ 'subitems': relationship(SubItem, backref='item', lazy=True)
})
mapper(SubItem, subitems)
mapper(Customer, customers, properties={
- 'purchases': relation(Purchase, lazy=True, backref='customer')
+ 'purchases': relationship(Purchase, lazy=True, backref='customer')
})
mapper(Purchase, purchases, properties={
- 'items': relation(Item, lazy=True, secondary=purchaseitems)
+ 'items': relationship(Item, lazy=True, secondary=purchaseitems)
})
@profiled('inserts')
pass
mapper(T1, t1, properties={
- 't2s':relation(T2, backref='t1')
+ 't2s':relationship(T2, backref='t1')
})
mapper(T2, t2)
foo()
time.sleep(.05)
-mapper(T1, t1, properties={'t2':relation(T2, backref="t1")})
+mapper(T1, t1, properties={'t2':relationship(T2, backref="t1")})
mapper(T2, t2)
print "START"
for j in range(0, 5):
# ways. this will also attach a 'blogs' property to the user mapper.
mapper(Blog, tables.blogs, properties={
'id':tables.blogs.c.blog_id,
- 'owner':relation(user.User, lazy=False,
+ 'owner':relationship(user.User, lazy=False,
backref=backref('blogs', cascade="all, delete-orphan")),
})
primary_key=[tables.topic_xref.c.post_id,
tables.topic_xref.c.topic_id],
properties={
- 'topic':relation(Topic, lazy=False),
+ 'topic':relationship(Topic, lazy=False),
})
# Post mapper, these are posts within a blog.
mapper(Post, posts_with_ccount, properties={
'id':posts_with_ccount.c.post_id,
'body':deferred(tables.posts.c.body),
- 'user':relation(user.User, lazy=True,
+ 'user':relationship(user.User, lazy=True,
backref=backref('posts', cascade="all, delete-orphan")),
- 'blog':relation(Blog, lazy=True,
+ 'blog':relationship(Blog, lazy=True,
backref=backref('posts', cascade="all, delete-orphan")),
- 'topics':relation(TopicAssociation, lazy=False,
+ 'topics':relationship(TopicAssociation, lazy=False,
cascade="all, delete-orphan",
backref='post')
}, order_by=[desc(posts_with_ccount.c.datetime)])
# list of child comments.
mapper(Comment, tables.comments, properties={
'id':tables.comments.c.comment_id,
- 'post':relation(Post, lazy=True,
+ 'post':relationship(Post, lazy=True,
backref=backref('comments',
cascade="all, delete-orphan")),
- 'user':relation(user.User, lazy=False,
+ 'user':relationship(user.User, lazy=False,
backref=backref('comments',
cascade="all, delete-orphan")),
- 'parent':relation(Comment,
+ 'parent':relationship(Comment,
primaryjoin=(tables.comments.c.parent_comment_id ==
tables.comments.c.comment_id),
foreign_keys=[tables.comments.c.comment_id],
lazy=True, uselist=False),
- 'replies':relation(Comment,
+ 'replies':relationship(Comment,
primaryjoin=(tables.comments.c.parent_comment_id ==
tables.comments.c.comment_id),
lazy=True, uselist=True, cascade="all"),