]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
modernize/update cascade documentation, [ticket:2302]
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 22 Jan 2012 23:32:41 +0000 (18:32 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 22 Jan 2012 23:32:41 +0000 (18:32 -0500)
doc/build/orm/session.rst

index 675b2136f14cccd14b8e5a371eee9da230a4f2a8..298f2ea29904b2a9036ad783b2a8942ae80777fc 100644 (file)
@@ -907,57 +907,137 @@ setting.
 Cascades
 ========
 
-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
+Mappers support the concept of configurable **cascade** behavior on
+:func:`~sqlalchemy.orm.relationship` constructs.  This refers
+to how operations performed on a parent object relative to a
+particular :class:`.Session` should be propagated to items
+referred to by that relationship.
+The default cascade behavior is usually suitable for 
+most situations, and the option is normally invoked explicitly
+in order to enable ``delete`` and ``delete-orphan`` cascades,
+which refer to how the relationship should be treated when
+the parent is marked for deletion as well as when a child
+is de-associated from its parent.
+
+Cascade behavior is configured by setting the ``cascade`` keyword 
+argument on 
 :func:`~sqlalchemy.orm.relationship`::
 
-    mapper(Order, order_table, properties={
-        'items' : relationship(Item, cascade="all, delete-orphan"),
-        'customer' : relationship(User, secondary=user_orders_table, cascade="save-update"),
-    })
-
-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 a session will also be added to that same session.
-"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.
-
-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, 
-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.relationship` is
-``save-update, merge``.
+    class Order(Base):
+        __tablename__ = 'order'
+
+        items = relationship("Item", cascade="all, delete-orphan")
+        customer = relationship("User", secondary=user_orders_table, 
+                                    cascade="save-update")
+
+To set cascades on a backref, the same flag can be used with the
+:func:`~.sqlalchemy.orm.backref` function, which ultimately feeds
+its arguments back into :func:`~sqlalchemy.orm.relationship`::
+
+    class Item(Base):
+        __tablename__ = 'item'
+
+        order = relationship("Order", 
+                        backref=backref("items", cascade="all, delete-orphan")
+                    )
+
+The default value of ``cascade`` is ``save-update, merge``.  
+The ``all`` symbol in the cascade options indicates that all
+cascade flags should be enabled, with the exception of ``delete-orphan``.
+Typically, cascade is usually left at its default, or configured
+as ``all, delete-orphan``, indicating the child objects should be
+treated as "owned" by the parent.
+
+The list of available values which can be specified in ``cascade``
+are as follows:
+
+* ``save-update`` - Indicates that when an object is placed into a 
+  :class:`.Session`
+  via :meth:`.Session.add`, all the objects associated with it via this
+  :func:`~sqlalchemy.orm.relationship` should also be added to that
+  same :class:`.Session`.   Additionally, if this object is already present in
+  a :class:`.Session`, child objects will be added to that session as they
+  are associated with this parent, i.e. as they are appended to lists,
+  added to sets, or otherwise associated with the parent.
+
+  ``save-update`` cascade also cascades the *pending history* of the
+  target 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 target session.  This
+  is because they may have foreign key attributes present which
+  will need to be updated to no longer refer to the parent. 
+
+  The ``save-update`` cascade is on by default, and it's common to not
+  even be aware of it.  It's customary that only a single call to
+  :meth:`.Session.add` against the lead object of a structure
+  has the effect of placing the full structure of 
+  objects into the :class:`.Session` at once.
+
+  However, it can be turned off, which would 
+  imply that objects associated with a parent would need to be 
+  placed individually using :meth:`.Session.add` calls for
+  each one.
+
+  Another default behavior of ``save-update`` cascade is that it will
+  take effect in the reverse direction, that is, associating a child
+  with a parent when a backref is present means both relationships
+  are affected; the parent will be added to the child's session.
+  To disable this somewhat indirect session addition, use the 
+  ``cascade_backrefs=False`` option described below in 
+  :ref:`backref_cascade`.
+
+* ``delete`` - This cascade indicates that when the parent object
+  is marked for deletion, the related objects should also be marked 
+  for deletion.   Without this cascade present, SQLAlchemy will
+  set the foreign key on a one-to-many relationship to NULL 
+  when the parent object is deleted.  When enabled, the row is instead
+  deleted.
+
+  ``delete`` cascade is often used in conjunction with ``delete-orphan``
+  cascade, as is appropriate for an object whose foreign key is
+  not intended to be nullable.  On some backends, it's also 
+  a good idea to set ``ON DELETE`` on the foreign key itself;
+  see the section :ref:`passive_deletes` for more details.
+
+  Note that for many-to-many relationships which make usage of the 
+  ``secondary`` argument to :func:`~.sqlalchemy.orm.relationship`, 
+  SQLAlchemy always emits
+  a DELETE for the association row in between "parent" and "child",
+  when the parent is deleted or whenever the linkage between a particular
+  parent and child is broken.
+
+* ``delete-orphan`` - This cascade adds behavior to the ``delete`` cascade,
+  such that a child object will be marked for deletion when it is
+  de-associated from the parent, not just when the parent is marked
+  for deletion.   This is a common feature when dealing with a related
+  object that is "owned" by its parent, with a NOT NULL foreign key,
+  so that removal of the item from the parent collection results
+  in its deletion.   
+
+  ``delete-orphan`` cascade implies that each child object can only 
+  have one parent at a time, so is configured in the vast majority of cases
+  on a one-to-many relationship.   Setting it on a many-to-one or 
+  many-to-many relationship is more awkward; for this use case, 
+  SQLAlchemy requires that the :func:`~sqlalchemy.orm.relationship`
+  be configured with the ``single_parent=True`` function, which 
+  establishes Python-side validation that ensures the object
+  is associated with only one parent at a time.
+
+* ``merge`` - This cascade indicates that the :meth:`.Session.merge`
+  operation should be propagated from a parent that's the subject
+  of the :meth:`.Session.merge` call down to referred objects. 
+  This cascade is also on by default.
+
+* ``refresh-expire`` - A less common option, indicates that the
+  :meth:`.Session.expire` operation should be propagated from a parent
+  down to referred objects.   When using :meth:`.Session.refresh`,
+  the referred objects are expired only, but not actually refreshed.
+
+* ``expunge`` - Indicate that when the parent object is removed
+  from the :class:`.Session` using :meth:`.Session.expunge`, the 
+  operation should be propagated down to referred objects.
+
+.. _backref_cascade:
 
 Controlling Cascade on Backrefs
 -------------------------------
@@ -1527,7 +1607,7 @@ across multiple databases::
 
 Above, operations against either class will make usage of the :class:`.Engine`
 linked to that class.   Upon a flush operation, similar rules take place
-to ensure each class is written to the right database.   
+to ensure each class is written to the right database.
 
 The transactions among the multiple databases can optionally be coordinated
 via two phase commit, if the underlying backend supports it.  See