1.. _collections_toplevel:
2
3.. currentmodule:: sqlalchemy.orm
4
5=======================================
6Collection Configuration and Techniques
7=======================================
8
9The :func:`.relationship` function defines a linkage between two classes.
10When the linkage defines a one-to-many or many-to-many relationship, it's
11represented as a Python collection when objects are loaded and manipulated.
12This section presents additional information about collection configuration
13and techniques.
14
15.. _largecollections:
16.. currentmodule:: sqlalchemy.orm
17
18Working with Large Collections
19==============================
20
21The default behavior of :func:`.relationship` is to fully load
22the collection of items in, as according to the loading strategy of the
23relationship. Additionally, the :class:`.Session` by default only knows how to delete
24objects which are actually present within the session. When a parent instance
25is marked for deletion and flushed, the :class:`.Session` loads its full list of child
26items in so that they may either be deleted as well, or have their foreign key
27value set to null; this is to avoid constraint violations. For large
28collections of child items, there are several strategies to bypass full
29loading of child items both at load time as well as deletion time.
30
31.. _dynamic_relationship:
32
33Dynamic Relationship Loaders
34----------------------------
35
36A key feature to enable management of a large collection is the so-called "dynamic"
37relationship.  This is an optional form of :func:`~sqlalchemy.orm.relationship` which
38returns a :class:`~sqlalchemy.orm.query.Query` object in place of a collection
39when accessed. :func:`~sqlalchemy.orm.query.Query.filter` criterion may be
40applied as well as limits and offsets, either explicitly or via array slices::
41
42    class User(Base):
43        __tablename__ = 'user'
44
45        posts = relationship(Post, lazy="dynamic")
46
47    jack = session.query(User).get(id)
48
49    # filter Jack's blog posts
50    posts = jack.posts.filter(Post.headline=='this is a post')
51
52    # apply array slices
53    posts = jack.posts[5:20]
54
55The dynamic relationship supports limited write operations, via the
56``append()`` and ``remove()`` methods::
57
58    oldpost = jack.posts.filter(Post.headline=='old post').one()
59    jack.posts.remove(oldpost)
60
61    jack.posts.append(Post('new post'))
62
63Since the read side of the dynamic relationship always queries the
64database, changes to the underlying collection will not be visible
65until the data has been flushed.  However, as long as "autoflush" is
66enabled on the :class:`.Session` in use, this will occur
67automatically each time the collection is about to emit a
68query.
69
70To place a dynamic relationship on a backref, use the :func:`~.orm.backref`
71function in conjunction with ``lazy='dynamic'``::
72
73    class Post(Base):
74        __table__ = posts_table
75
76        user = relationship(User,
77                    backref=backref('posts', lazy='dynamic')
78                )
79
80Note that eager/lazy loading options cannot be used in conjunction dynamic relationships at this time.
81
82.. note::
83
84   The :func:`~.orm.dynamic_loader` function is essentially the same
85   as :func:`~.orm.relationship` with the ``lazy='dynamic'`` argument specified.
86
87.. warning::
88
89   The "dynamic" loader applies to **collections only**.   It is not valid
90   to use "dynamic" loaders with many-to-one, one-to-one, or uselist=False
91   relationships.   Newer versions of SQLAlchemy emit warnings or exceptions
92   in these cases.
93
94.. _collections_noload_raiseload:
95
96Setting Noload, RaiseLoad
97-------------------------
98
99A "noload" relationship never loads from the database, even when
100accessed.   It is configured using ``lazy='noload'``::
101
102    class MyClass(Base):
103        __tablename__ = 'some_table'
104
105        children = relationship(MyOtherClass, lazy='noload')
106
107Above, the ``children`` collection is fully writeable, and changes to it will
108be persisted to the database as well as locally available for reading at the
109time they are added. However when instances of ``MyClass`` are freshly loaded
110from the database, the ``children`` collection stays empty.   The noload
111strategy is also available on a query option basis using the
112:func:`.orm.noload` loader option.
113
114Alternatively, a "raise"-loaded relationship will raise an
115:exc:`~sqlalchemy.exc.InvalidRequestError` where the attribute would normally
116emit a lazy load::
117
118    class MyClass(Base):
119        __tablename__ = 'some_table'
120
121        children = relationship(MyOtherClass, lazy='raise')
122
123Above, attribute access on the ``children`` collection will raise an exception
124if it was not previously eagerloaded.  This includes read access but for
125collections will also affect write access, as collections can't be mutated
126without first loading them.  The rationale for this is to ensure that an
127application is not emitting any unexpected lazy loads within a certain context.
128Rather than having to read through SQL logs to determine that all necessary
129attributes were eager loaded, the "raise" strategy will cause unloaded
130attributes to raise immediately if accessed.  The raise strategy is
131also available on a query option basis using the :func:`.orm.raiseload`
132loader option.
133
134.. versionadded:: 1.1 added the "raise" loader strategy.
135
136.. seealso::
137
138    :ref:`prevent_lazy_with_raiseload`
139
140.. _passive_deletes:
141
142Using Passive Deletes
143---------------------
144
145Use :paramref:`~.relationship.passive_deletes` to disable child object loading on a DELETE
146operation, in conjunction with "ON DELETE (CASCADE|SET NULL)" on your database
147to automatically cascade deletes to child objects::
148
149    class MyClass(Base):
150        __tablename__ = 'mytable'
151        id = Column(Integer, primary_key=True)
152        children = relationship("MyOtherClass",
153                        cascade="all, delete-orphan",
154                        passive_deletes=True)
155
156    class MyOtherClass(Base):
157        __tablename__ = 'myothertable'
158        id = Column(Integer, primary_key=True)
159        parent_id = Column(Integer,
160                    ForeignKey('mytable.id', ondelete='CASCADE')
161                        )
162
163
164.. note::
165
166    To use "ON DELETE CASCADE", the underlying database engine must
167    support foreign keys.
168
169    * When using MySQL, an appropriate storage engine must be
170      selected.  See :ref:`mysql_storage_engines` for details.
171
172    * When using SQLite, foreign key support must be enabled explicitly.
173      See :ref:`sqlite_foreign_keys` for details.
174
175When :paramref:`~.relationship.passive_deletes` is applied, the ``children`` relationship will not be
176loaded into memory when an instance of ``MyClass`` is marked for deletion. The
177``cascade="all, delete-orphan"`` *will* take effect for instances of
178``MyOtherClass`` which are currently present in the session; however for
179instances of ``MyOtherClass`` which are not loaded, SQLAlchemy assumes that
180"ON DELETE CASCADE" rules will ensure that those rows are deleted by the
181database.
182
183.. seealso::
184
185    :paramref:`.orm.mapper.passive_deletes` - similar feature on :func:`.mapper`
186
187.. currentmodule:: sqlalchemy.orm.collections
188.. _custom_collections:
189
190Customizing Collection Access
191=============================
192
193Mapping a one-to-many or many-to-many relationship results in a collection of
194values accessible through an attribute on the parent instance. By default,
195this collection is a ``list``::
196
197    class Parent(Base):
198        __tablename__ = 'parent'
199        parent_id = Column(Integer, primary_key=True)
200
201        children = relationship(Child)
202
203    parent = Parent()
204    parent.children.append(Child())
205    print(parent.children[0])
206
207Collections are not limited to lists. Sets, mutable sequences and almost any
208other Python object that can act as a container can be used in place of the
209default list, by specifying the :paramref:`~.relationship.collection_class` option on
210:func:`~sqlalchemy.orm.relationship`::
211
212    class Parent(Base):
213        __tablename__ = 'parent'
214        parent_id = Column(Integer, primary_key=True)
215
216        # use a set
217        children = relationship(Child, collection_class=set)
218
219    parent = Parent()
220    child = Child()
221    parent.children.add(child)
222    assert child in parent.children
223
224Dictionary Collections
225----------------------
226
227A little extra detail is needed when using a dictionary as a collection.
228This because objects are always loaded from the database as lists, and a key-generation
229strategy must be available to populate the dictionary correctly.  The
230:func:`.attribute_mapped_collection` function is by far the most common way
231to achieve a simple dictionary collection.  It produces a dictionary class that will apply a particular attribute
232of the mapped class as a key.   Below we map an ``Item`` class containing
233a dictionary of ``Note`` items keyed to the ``Note.keyword`` attribute::
234
235    from sqlalchemy import Column, Integer, String, ForeignKey
236    from sqlalchemy.orm import relationship
237    from sqlalchemy.orm.collections import attribute_mapped_collection
238    from sqlalchemy.ext.declarative import declarative_base
239
240    Base = declarative_base()
241
242    class Item(Base):
243        __tablename__ = 'item'
244        id = Column(Integer, primary_key=True)
245        notes = relationship("Note",
246                    collection_class=attribute_mapped_collection('keyword'),
247                    cascade="all, delete-orphan")
248
249    class Note(Base):
250        __tablename__ = 'note'
251        id = Column(Integer, primary_key=True)
252        item_id = Column(Integer, ForeignKey('item.id'), nullable=False)
253        keyword = Column(String)
254        text = Column(String)
255
256        def __init__(self, keyword, text):
257            self.keyword = keyword
258            self.text = text
259
260``Item.notes`` is then a dictionary::
261
262    >>> item = Item()
263    >>> item.notes['a'] = Note('a', 'atext')
264    >>> item.notes.items()
265    {'a': <__main__.Note object at 0x2eaaf0>}
266
267:func:`.attribute_mapped_collection` will ensure that
268the ``.keyword`` attribute of each ``Note`` complies with the key in the
269dictionary.   Such as, when assigning to ``Item.notes``, the dictionary
270key we supply must match that of the actual ``Note`` object::
271
272    item = Item()
273    item.notes = {
274                'a': Note('a', 'atext'),
275                'b': Note('b', 'btext')
276            }
277
278The attribute which :func:`.attribute_mapped_collection` uses as a key
279does not need to be mapped at all!  Using a regular Python ``@property`` allows virtually
280any detail or combination of details about the object to be used as the key, as
281below when we establish it as a tuple of ``Note.keyword`` and the first ten letters
282of the ``Note.text`` field::
283
284    class Item(Base):
285        __tablename__ = 'item'
286        id = Column(Integer, primary_key=True)
287        notes = relationship("Note",
288                    collection_class=attribute_mapped_collection('note_key'),
289                    backref="item",
290                    cascade="all, delete-orphan")
291
292    class Note(Base):
293        __tablename__ = 'note'
294        id = Column(Integer, primary_key=True)
295        item_id = Column(Integer, ForeignKey('item.id'), nullable=False)
296        keyword = Column(String)
297        text = Column(String)
298
299        @property
300        def note_key(self):
301            return (self.keyword, self.text[0:10])
302
303        def __init__(self, keyword, text):
304            self.keyword = keyword
305            self.text = text
306
307Above we added a ``Note.item`` backref.  Assigning to this reverse relationship, the ``Note``
308is added to the ``Item.notes`` dictionary and the key is generated for us automatically::
309
310    >>> item = Item()
311    >>> n1 = Note("a", "atext")
312    >>> n1.item = item
313    >>> item.notes
314    {('a', 'atext'): <__main__.Note object at 0x2eaaf0>}
315
316Other built-in dictionary types include :func:`.column_mapped_collection`,
317which is almost like :func:`.attribute_mapped_collection` except given the :class:`.Column`
318object directly::
319
320    from sqlalchemy.orm.collections import column_mapped_collection
321
322    class Item(Base):
323        __tablename__ = 'item'
324        id = Column(Integer, primary_key=True)
325        notes = relationship("Note",
326                    collection_class=column_mapped_collection(Note.__table__.c.keyword),
327                    cascade="all, delete-orphan")
328
329as well as :func:`.mapped_collection` which is passed any callable function.
330Note that it's usually easier to use :func:`.attribute_mapped_collection` along
331with a ``@property`` as mentioned earlier::
332
333    from sqlalchemy.orm.collections import mapped_collection
334
335    class Item(Base):
336        __tablename__ = 'item'
337        id = Column(Integer, primary_key=True)
338        notes = relationship("Note",
339                    collection_class=mapped_collection(lambda note: note.text[0:10]),
340                    cascade="all, delete-orphan")
341
342Dictionary mappings are often combined with the "Association Proxy" extension to produce
343streamlined dictionary views.  See :ref:`proxying_dictionaries` and :ref:`composite_association_proxy`
344for examples.
345
346.. autofunction:: attribute_mapped_collection
347
348.. autofunction:: column_mapped_collection
349
350.. autofunction:: mapped_collection
351
352Custom Collection Implementations
353=================================
354
355You can use your own types for collections as well.  In simple cases,
356inherting from ``list`` or ``set``, adding custom behavior, is all that's needed.
357In other cases, special decorators are needed to tell SQLAlchemy more detail
358about how the collection operates.
359
360.. topic:: Do I need a custom collection implementation?
361
362   In most cases not at all!   The most common use cases for a "custom" collection
363   is one that validates or marshals incoming values into a new form, such as
364   a string that becomes a class instance, or one which goes a
365   step beyond and represents the data internally in some fashion, presenting
366   a "view" of that data on the outside of a different form.
367
368   For the first use case, the :func:`.orm.validates` decorator is by far
369   the simplest way to intercept incoming values in all cases for the purposes
370   of validation and simple marshaling.  See :ref:`simple_validators`
371   for an example of this.
372
373   For the second use case, the :ref:`associationproxy_toplevel` extension is a
374   well-tested, widely used system that provides a read/write "view" of a
375   collection in terms of some attribute present on the target object. As the
376   target attribute can be a ``@property`` that returns virtually anything, a
377   wide array of "alternative" views of a collection can be constructed with
378   just a few functions. This approach leaves the underlying mapped collection
379   unaffected and avoids the need to carefully tailor collection behavior on a
380   method-by-method basis.
381
382   Customized collections are useful when the collection needs to
383   have special behaviors upon access or mutation operations that can't
384   otherwise be modeled externally to the collection.   They can of course
385   be combined with the above two approaches.
386
387Collections in SQLAlchemy are transparently *instrumented*. Instrumentation
388means that normal operations on the collection are tracked and result in
389changes being written to the database at flush time. Additionally, collection
390operations can fire *events* which indicate some secondary operation must take
391place. Examples of a secondary operation include saving the child item in the
392parent's :class:`~sqlalchemy.orm.session.Session` (i.e. the ``save-update``
393cascade), as well as synchronizing the state of a bi-directional relationship
394(i.e. a :func:`.backref`).
395
396The collections package understands the basic interface of lists, sets and
397dicts and will automatically apply instrumentation to those built-in types and
398their subclasses. Object-derived types that implement a basic collection
399interface are detected and instrumented via duck-typing:
400
401.. sourcecode:: python+sql
402
403    class ListLike(object):
404        def __init__(self):
405            self.data = []
406        def append(self, item):
407            self.data.append(item)
408        def remove(self, item):
409            self.data.remove(item)
410        def extend(self, items):
411            self.data.extend(items)
412        def __iter__(self):
413            return iter(self.data)
414        def foo(self):
415            return 'foo'
416
417``append``, ``remove``, and ``extend`` are known list-like methods, and will
418be instrumented automatically. ``__iter__`` is not a mutator method and won't
419be instrumented, and ``foo`` won't be either.
420
421Duck-typing (i.e. guesswork) isn't rock-solid, of course, so you can be
422explicit about the interface you are implementing by providing an
423``__emulates__`` class attribute::
424
425    class SetLike(object):
426        __emulates__ = set
427
428        def __init__(self):
429            self.data = set()
430        def append(self, item):
431            self.data.add(item)
432        def remove(self, item):
433            self.data.remove(item)
434        def __iter__(self):
435            return iter(self.data)
436
437This class looks list-like because of ``append``, but ``__emulates__`` forces
438it to set-like. ``remove`` is known to be part of the set interface and will
439be instrumented.
440
441But this class won't work quite yet: a little glue is needed to adapt it for
442use by SQLAlchemy. The ORM needs to know which methods to use to append,
443remove and iterate over members of the collection. When using a type like
444``list`` or ``set``, the appropriate methods are well-known and used
445automatically when present. This set-like class does not provide the expected
446``add`` method, so we must supply an explicit mapping for the ORM via a
447decorator.
448
449Annotating Custom Collections via Decorators
450--------------------------------------------
451
452Decorators can be used to tag the individual methods the ORM needs to manage
453collections. Use them when your class doesn't quite meet the regular interface
454for its container type, or when you otherwise would like to use a different method to
455get the job done.
456
457.. sourcecode:: python
458
459    from sqlalchemy.orm.collections import collection
460
461    class SetLike(object):
462        __emulates__ = set
463
464        def __init__(self):
465            self.data = set()
466
467        @collection.appender
468        def append(self, item):
469            self.data.add(item)
470
471        def remove(self, item):
472            self.data.remove(item)
473
474        def __iter__(self):
475            return iter(self.data)
476
477And that's all that's needed to complete the example. SQLAlchemy will add
478instances via the ``append`` method. ``remove`` and ``__iter__`` are the
479default methods for sets and will be used for removing and iteration. Default
480methods can be changed as well:
481
482.. sourcecode:: python+sql
483
484    from sqlalchemy.orm.collections import collection
485
486    class MyList(list):
487        @collection.remover
488        def zark(self, item):
489            # do something special...
490
491        @collection.iterator
492        def hey_use_this_instead_for_iteration(self):
493            # ...
494
495There is no requirement to be list-, or set-like at all. Collection classes
496can be any shape, so long as they have the append, remove and iterate
497interface marked for SQLAlchemy's use. Append and remove methods will be
498called with a mapped entity as the single argument, and iterator methods are
499called with no arguments and must return an iterator.
500
501.. autoclass:: collection
502    :members:
503
504.. _dictionary_collections:
505
506Custom Dictionary-Based Collections
507-----------------------------------
508
509The :class:`.MappedCollection` class can be used as
510a base class for your custom types or as a mix-in to quickly add ``dict``
511collection support to other classes. It uses a keying function to delegate to
512``__setitem__`` and ``__delitem__``:
513
514.. sourcecode:: python+sql
515
516    from sqlalchemy.util import OrderedDict
517    from sqlalchemy.orm.collections import MappedCollection
518
519    class NodeMap(OrderedDict, MappedCollection):
520        """Holds 'Node' objects, keyed by the 'name' attribute with insert order maintained."""
521
522        def __init__(self, *args, **kw):
523            MappedCollection.__init__(self, keyfunc=lambda node: node.name)
524            OrderedDict.__init__(self, *args, **kw)
525
526When subclassing :class:`.MappedCollection`, user-defined versions
527of ``__setitem__()`` or ``__delitem__()`` should be decorated
528with :meth:`.collection.internally_instrumented`, **if** they call down
529to those same methods on :class:`.MappedCollection`.  This because the methods
530on :class:`.MappedCollection` are already instrumented - calling them
531from within an already instrumented call can cause events to be fired off
532repeatedly, or inappropriately, leading to internal state corruption in
533rare cases::
534
535    from sqlalchemy.orm.collections import MappedCollection,\
536                                        collection
537
538    class MyMappedCollection(MappedCollection):
539        """Use @internally_instrumented when your methods
540        call down to already-instrumented methods.
541
542        """
543
544        @collection.internally_instrumented
545        def __setitem__(self, key, value, _sa_initiator=None):
546            # do something with key, value
547            super(MyMappedCollection, self).__setitem__(key, value, _sa_initiator)
548
549        @collection.internally_instrumented
550        def __delitem__(self, key, _sa_initiator=None):
551            # do something with key
552            super(MyMappedCollection, self).__delitem__(key, _sa_initiator)
553
554The ORM understands the ``dict`` interface just like lists and sets, and will
555automatically instrument all dict-like methods if you choose to subclass
556``dict`` or provide dict-like collection behavior in a duck-typed class. You
557must decorate appender and remover methods, however- there are no compatible
558methods in the basic dictionary interface for SQLAlchemy to use by default.
559Iteration will go through ``itervalues()`` unless otherwise decorated.
560
561.. note::
562
563   Due to a bug in MappedCollection prior to version 0.7.6, this
564   workaround usually needs to be called before a custom subclass
565   of :class:`.MappedCollection` which uses :meth:`.collection.internally_instrumented`
566   can be used::
567
568    from sqlalchemy.orm.collections import _instrument_class, MappedCollection
569    _instrument_class(MappedCollection)
570
571   This will ensure that the :class:`.MappedCollection` has been properly
572   initialized with custom ``__setitem__()`` and ``__delitem__()``
573   methods before used in a custom subclass.
574
575.. autoclass:: sqlalchemy.orm.collections.MappedCollection
576   :members:
577
578Instrumentation and Custom Types
579--------------------------------
580
581Many custom types and existing library classes can be used as a entity
582collection type as-is without further ado. However, it is important to note
583that the instrumentation process will modify the type, adding decorators
584around methods automatically.
585
586The decorations are lightweight and no-op outside of relationships, but they
587do add unneeded overhead when triggered elsewhere. When using a library class
588as a collection, it can be good practice to use the "trivial subclass" trick
589to restrict the decorations to just your usage in relationships. For example:
590
591.. sourcecode:: python+sql
592
593    class MyAwesomeList(some.great.library.AwesomeList):
594        pass
595
596    # ... relationship(..., collection_class=MyAwesomeList)
597
598The ORM uses this approach for built-ins, quietly substituting a trivial
599subclass when a ``list``, ``set`` or ``dict`` is used directly.
600
601Collection Internals
602====================
603
604Various internal methods.
605
606.. autofunction:: bulk_replace
607
608.. autoclass:: collection
609
610.. autodata:: collection_adapter
611
612.. autoclass:: CollectionAdapter
613
614.. autoclass:: InstrumentedDict
615
616.. autoclass:: InstrumentedList
617
618.. autoclass:: InstrumentedSet
619
620.. autofunction:: prepare_instrumentation
621