~ubuntu-branches/debian/sid/sqlalchemy/sid

« back to all changes in this revision

Viewing changes to doc/build/orm/relationships.rst

  • Committer: Bazaar Package Importer
  • Author(s): Piotr Ożarowski
  • Date: 2011-10-18 00:02:50 UTC
  • mfrom: (1.4.16 upstream)
  • Revision ID: james.westby@ubuntu.com-20111018000250-prowqcleosluapxg
Tags: 0.7.3-2
remove build-indep from build target's dependencies (closes: 645697)

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
:ref:`collections_toplevel`, which has additional detail on configuration
11
11
of collections via :func:`relationship`.
12
12
 
 
13
.. _relationship_patterns:
 
14
 
13
15
Basic Relational Patterns
14
16
--------------------------
15
17
 
16
 
A quick walkthrough of the basic relational patterns. In this section we
17
 
illustrate the classical mapping using :func:`mapper` in conjunction with
18
 
:func:`relationship`. Then (by popular demand), we illustrate the declarative
19
 
form using the :mod:`~sqlalchemy.ext.declarative` module.
20
 
 
21
 
Note that :func:`.relationship` is historically known as
22
 
:func:`.relation` in older versions of SQLAlchemy.
 
18
A quick walkthrough of the basic relational patterns. 
 
19
 
 
20
The imports used for each of the following sections is as follows::
 
21
 
 
22
    from sqlalchemy import Table, Column, Integer, ForeignKey
 
23
    from sqlalchemy.orm import relationship, backref
 
24
    from sqlalchemy.ext.declarative import declarative_base
 
25
 
 
26
    Base = declarative_base()
 
27
 
23
28
 
24
29
One To Many
25
30
~~~~~~~~~~~~
26
31
 
27
 
A one to many relationship places a foreign key in the child table referencing
28
 
the parent. SQLAlchemy creates the relationship as a collection on the parent
29
 
object containing instances of the child object.
30
 
 
31
 
.. sourcecode:: python+sql
32
 
 
33
 
    parent_table = Table('parent', metadata,
34
 
        Column('id', Integer, primary_key=True))
35
 
 
36
 
    child_table = Table('child', metadata,
37
 
        Column('id', Integer, primary_key=True),
38
 
        Column('parent_id', Integer, ForeignKey('parent.id'))
39
 
    )
40
 
 
41
 
    class Parent(object):
42
 
        pass
43
 
 
44
 
    class Child(object):
45
 
        pass
46
 
 
47
 
    mapper(Parent, parent_table, properties={
48
 
        'children': relationship(Child)
49
 
    })
50
 
 
51
 
    mapper(Child, child_table)
52
 
 
53
 
To establish a bi-directional relationship in one-to-many, where the "reverse" side is a many to one, specify the ``backref`` option:
54
 
 
55
 
.. sourcecode:: python+sql
56
 
 
57
 
    mapper(Parent, parent_table, properties={
58
 
        'children': relationship(Child, backref='parent')
59
 
    })
60
 
 
61
 
    mapper(Child, child_table)
 
32
A one to many relationship places a foreign key on the child table referencing
 
33
the parent.  :func:`.relationship` is then specified on the parent, as referencing
 
34
a collection of items represented by the child::
 
35
 
 
36
    class Parent(Base):
 
37
        __tablename__ = 'parent'
 
38
        id = Column(Integer, primary_key=True)
 
39
        children = relationship("Child")
 
40
 
 
41
    class Child(Base):
 
42
        __tablename__ = 'child'
 
43
        id = Column(Integer, primary_key=True)
 
44
        parent_id = Column(Integer, ForeignKey('parent.id'))
 
45
 
 
46
To establish a bidirectional relationship in one-to-many, where the "reverse"
 
47
side is a many to one, specify the ``backref`` option::
 
48
 
 
49
    class Parent(Base):
 
50
        __tablename__ = 'parent'
 
51
        id = Column(Integer, primary_key=True)
 
52
        children = relationship("Child", backref="parent")
 
53
 
 
54
    class Child(Base):
 
55
        __tablename__ = 'child'
 
56
        id = Column(Integer, primary_key=True)
 
57
        parent_id = Column(Integer, ForeignKey('parent.id'))
62
58
 
63
59
``Child`` will get a ``parent`` attribute with many-to-one semantics.
64
60
 
65
 
Declarative::
66
 
 
67
 
    from sqlalchemy.ext.declarative import declarative_base
68
 
    Base = declarative_base()
69
 
 
70
 
    class Parent(Base):
71
 
        __tablename__ = 'parent'
72
 
        id = Column(Integer, primary_key=True)
73
 
        children = relationship("Child", backref="parent")
74
 
 
75
 
    class Child(Base):
76
 
        __tablename__ = 'child'
77
 
        id = Column(Integer, primary_key=True)
78
 
        parent_id = Column(Integer, ForeignKey('parent.id'))
79
 
 
80
 
 
81
61
Many To One
82
62
~~~~~~~~~~~~
83
63
 
84
64
Many to one places a foreign key in the parent table referencing the child.
85
 
The mapping setup is identical to one-to-many, however SQLAlchemy creates the
86
 
relationship as a scalar attribute on the parent object referencing a single
87
 
instance of the child object.
88
 
 
89
 
.. sourcecode:: python+sql
90
 
 
91
 
    parent_table = Table('parent', metadata,
92
 
        Column('id', Integer, primary_key=True),
93
 
        Column('child_id', Integer, ForeignKey('child.id')))
94
 
 
95
 
    child_table = Table('child', metadata,
96
 
        Column('id', Integer, primary_key=True),
97
 
        )
98
 
 
99
 
    class Parent(object):
100
 
        pass
101
 
 
102
 
    class Child(object):
103
 
        pass
104
 
 
105
 
    mapper(Parent, parent_table, properties={
106
 
        'child': relationship(Child)
107
 
    })
108
 
 
109
 
    mapper(Child, child_table)
110
 
 
111
 
Backref behavior is available here as well, where ``backref="parents"`` will
112
 
place a one-to-many collection on the ``Child`` class::
113
 
 
114
 
    mapper(Parent, parent_table, properties={
115
 
        'child': relationship(Child, backref="parents")
116
 
    })
117
 
 
118
 
Declarative::
119
 
 
120
 
    from sqlalchemy.ext.declarative import declarative_base
121
 
    Base = declarative_base()
 
65
:func:`.relationship` is declared on the parent, where a new scalar-holding
 
66
attribute will be created::
 
67
 
 
68
    class Parent(Base):
 
69
        __tablename__ = 'parent'
 
70
        id = Column(Integer, primary_key=True)
 
71
        child_id = Column(Integer, ForeignKey('child.id'))
 
72
        child = relationship("Child")
 
73
 
 
74
    class Child(Base):
 
75
        __tablename__ = 'child'
 
76
        id = Column(Integer, primary_key=True)
 
77
 
 
78
Bidirectional behavior is achieved by specifying ``backref="parents"``,
 
79
which will place a one-to-many collection on the ``Child`` class::
122
80
 
123
81
    class Parent(Base):
124
82
        __tablename__ = 'parent'
126
84
        child_id = Column(Integer, ForeignKey('child.id'))
127
85
        child = relationship("Child", backref="parents")
128
86
 
129
 
    class Child(Base):
130
 
        __tablename__ = 'child'
131
 
        id = Column(Integer, primary_key=True)
132
 
 
133
87
One To One
134
88
~~~~~~~~~~~
135
89
 
136
 
One To One is essentially a bi-directional relationship with a scalar
 
90
One To One is essentially a bidirectional relationship with a scalar
137
91
attribute on both sides. To achieve this, the ``uselist=False`` flag indicates
138
92
the placement of a scalar attribute instead of a collection on the "many" side
139
93
of the relationship. To convert one-to-many into one-to-one::
140
94
 
141
 
    parent_table = Table('parent', metadata,
142
 
        Column('id', Integer, primary_key=True)
143
 
    )
144
 
 
145
 
    child_table = Table('child', metadata,
146
 
        Column('id', Integer, primary_key=True),
147
 
        Column('parent_id', Integer, ForeignKey('parent.id'))
148
 
    )
149
 
 
150
 
    mapper(Parent, parent_table, properties={
151
 
        'child': relationship(Child, uselist=False, backref='parent')
152
 
    })
153
 
 
154
 
    mapper(Child, child_table)
 
95
    class Parent(Base):
 
96
        __tablename__ = 'parent'
 
97
        id = Column(Integer, primary_key=True)
 
98
        child = relationship("Child", uselist=False, backref="parent")
 
99
 
 
100
    class Child(Base):
 
101
        __tablename__ = 'child'
 
102
        id = Column(Integer, primary_key=True)
 
103
        parent_id = Column(Integer, ForeignKey('parent.id'))
155
104
 
156
105
Or to turn a one-to-many backref into one-to-one, use the :func:`.backref` function
157
106
to provide arguments for the reverse side::
158
107
 
159
 
    from sqlalchemy.orm import backref
160
 
 
161
 
    parent_table = Table('parent', metadata,
162
 
        Column('id', Integer, primary_key=True),
163
 
        Column('child_id', Integer, ForeignKey('child.id'))
164
 
    )
165
 
 
166
 
    child_table = Table('child', metadata,
167
 
        Column('id', Integer, primary_key=True)
168
 
    )
169
 
 
170
 
    mapper(Parent, parent_table, properties={
171
 
        'child': relationship(Child, backref=backref('parent', uselist=False))
172
 
    })
173
 
 
174
 
    mapper(Child, child_table)
175
 
 
176
 
The second example above as declarative::
177
 
 
178
 
    from sqlalchemy.ext.declarative import declarative_base
179
 
    Base = declarative_base()
180
 
 
181
108
    class Parent(Base):
182
109
        __tablename__ = 'parent'
183
110
        id = Column(Integer, primary_key=True)
188
115
        __tablename__ = 'child'
189
116
        id = Column(Integer, primary_key=True)
190
117
 
 
118
.. _relationships_many_to_many:
 
119
 
191
120
Many To Many
192
121
~~~~~~~~~~~~~
193
122
 
194
123
Many to Many adds an association table between two classes. The association
195
124
table is indicated by the ``secondary`` argument to
196
 
:func:`.relationship`.
197
 
 
198
 
.. sourcecode:: python+sql
199
 
 
200
 
    left_table = Table('left', metadata,
201
 
        Column('id', Integer, primary_key=True)
202
 
    )
203
 
 
204
 
    right_table = Table('right', metadata,
205
 
        Column('id', Integer, primary_key=True)
206
 
    )
207
 
 
208
 
    association_table = Table('association', metadata,
 
125
:func:`.relationship`.  Usually, the :class:`.Table` uses the :class:`.MetaData`
 
126
object associated with the declarative base class, so that the :class:`.ForeignKey`
 
127
directives can locate the remote tables with which to link::
 
128
 
 
129
    association_table = Table('association', Base.metadata,
209
130
        Column('left_id', Integer, ForeignKey('left.id')),
210
131
        Column('right_id', Integer, ForeignKey('right.id'))
211
132
    )
212
133
 
213
 
    mapper(Parent, left_table, properties={
214
 
        'children': relationship(Child, secondary=association_table)
215
 
    })
216
 
 
217
 
    mapper(Child, right_table)
218
 
 
219
 
For a bi-directional relationship, both sides of the relationship contain a
 
134
    class Parent(Base):
 
135
        __tablename__ = 'left'
 
136
        id = Column(Integer, primary_key=True)
 
137
        children = relationship("Child", 
 
138
                        secondary=association_table)
 
139
 
 
140
    class Child(Base):
 
141
        __tablename__ = 'right'
 
142
        id = Column(Integer, primary_key=True)
 
143
 
 
144
For a bidirectional relationship, both sides of the relationship contain a
220
145
collection.  The ``backref`` keyword will automatically use
221
 
the same ``secondary`` argument for the reverse relationship:
222
 
 
223
 
.. sourcecode:: python+sql
224
 
 
225
 
    mapper(Parent, left_table, properties={
226
 
        'children': relationship(Child, secondary=association_table, 
227
 
                                        backref='parents')
228
 
    })
229
 
 
230
 
With declarative, we still use the :class:`.Table` for the ``secondary`` 
231
 
argument.  A class is not mapped to this table, so it remains in its 
232
 
plain schematic form::
233
 
 
234
 
    from sqlalchemy.ext.declarative import declarative_base
235
 
    Base = declarative_base()
 
146
the same ``secondary`` argument for the reverse relationship::
236
147
 
237
148
    association_table = Table('association', Base.metadata,
238
149
        Column('left_id', Integer, ForeignKey('left.id')),
250
161
        __tablename__ = 'right'
251
162
        id = Column(Integer, primary_key=True)
252
163
 
 
164
The ``secondary`` argument of :func:`.relationship` also accepts a callable
 
165
that returns the ultimate argument, which is evaluated only when mappers are 
 
166
first used.   Using this, we can define the ``association_table`` at a later
 
167
point, as long as it's available to the callable after all module initialization
 
168
is complete::
 
169
 
 
170
    class Parent(Base):
 
171
        __tablename__ = 'left'
 
172
        id = Column(Integer, primary_key=True)
 
173
        children = relationship("Child", 
 
174
                        secondary=lambda: association_table, 
 
175
                        backref="parents")
 
176
 
253
177
.. _association_pattern:
254
178
 
255
179
Association Object
261
185
``secondary`` argument, you map a new class directly to the association table.
262
186
The left side of the relationship references the association object via
263
187
one-to-many, and the association class references the right side via
264
 
many-to-one.
265
 
 
266
 
.. sourcecode:: python+sql
267
 
 
268
 
    left_table = Table('left', metadata,
269
 
        Column('id', Integer, primary_key=True)
270
 
    )
271
 
 
272
 
    right_table = Table('right', metadata,
273
 
        Column('id', Integer, primary_key=True)
274
 
    )
275
 
 
276
 
    association_table = Table('association', metadata,
277
 
        Column('left_id', Integer, ForeignKey('left.id'), primary_key=True),
278
 
        Column('right_id', Integer, ForeignKey('right.id'), primary_key=True),
279
 
        Column('data', String(50))
280
 
    )
281
 
 
282
 
    mapper(Parent, left_table, properties={
283
 
        'children':relationship(Association)
284
 
    })
285
 
 
286
 
    mapper(Association, association_table, properties={
287
 
        'child':relationship(Child)
288
 
    })
289
 
 
290
 
    mapper(Child, right_table)
291
 
 
292
 
The bi-directional version adds backrefs to both relationships:
293
 
 
294
 
.. sourcecode:: python+sql
295
 
 
296
 
    mapper(Parent, left_table, properties={
297
 
        'children':relationship(Association, backref="parent")
298
 
    })
299
 
 
300
 
    mapper(Association, association_table, properties={
301
 
        'child':relationship(Child, backref="parent_assocs")
302
 
    })
303
 
 
304
 
    mapper(Child, right_table)
305
 
 
306
 
Declarative::
307
 
 
308
 
    from sqlalchemy.ext.declarative import declarative_base
309
 
    Base = declarative_base()
 
188
many-to-one::
 
189
 
 
190
    class Association(Base):
 
191
        __tablename__ = 'association'
 
192
        left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
 
193
        right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
 
194
        child = relationship("Child")
 
195
 
 
196
    class Parent(Base):
 
197
        __tablename__ = 'left'
 
198
        id = Column(Integer, primary_key=True)
 
199
        children = relationship("Association")
 
200
 
 
201
    class Child(Base):
 
202
        __tablename__ = 'right'
 
203
        id = Column(Integer, primary_key=True)
 
204
 
 
205
The bidirectional version adds backrefs to both relationships::
310
206
 
311
207
    class Association(Base):
312
208
        __tablename__ = 'association'
317
213
    class Parent(Base):
318
214
        __tablename__ = 'left'
319
215
        id = Column(Integer, primary_key=True)
320
 
        children = relationship(Association, backref="parent")
 
216
        children = relationship("Association", backref="parent")
321
217
 
322
218
    class Child(Base):
323
219
        __tablename__ = 'right'
326
222
Working with the association pattern in its direct form requires that child
327
223
objects are associated with an association instance before being appended to
328
224
the parent; similarly, access from parent to child goes through the
329
 
association object:
330
 
 
331
 
.. sourcecode:: python+sql
 
225
association object::
332
226
 
333
227
    # create parent, append a child via association
334
228
    p = Parent()
344
238
 
345
239
To enhance the association object pattern such that direct
346
240
access to the ``Association`` object is optional, SQLAlchemy
347
 
provides the :ref:`associationproxy` extension. This
 
241
provides the :ref:`associationproxy_toplevel` extension. This
348
242
extension allows the configuration of attributes which will
349
243
access two "hops" with a single access, one "hop" to the
350
244
associated object, and a second to a target attribute.
363
257
-----------------------------
364
258
 
365
259
The **adjacency list** pattern is a common relational pattern whereby a table
366
 
contains a foreign key reference to itself. This is the most common and simple
367
 
way to represent hierarchical data in flat tables. The other way is the
368
 
"nested sets" model, sometimes called "modified preorder". Despite what many
369
 
online articles say about modified preorder, the adjacency list model is
 
260
contains a foreign key reference to itself. This is the most common 
 
261
way to represent hierarchical data in flat tables.  Other methods
 
262
include **nested sets**, sometimes called "modified preorder",
 
263
as well as **materialized path**.  Despite the appeal that modified preorder
 
264
has when evaluated for its fluency within SQL queries, the adjacency list model is
370
265
probably the most appropriate pattern for the large majority of hierarchical
371
266
storage needs, for reasons of concurrency, reduced complexity, and that
372
267
modified preorder has little advantage over an application which can fully
373
268
load subtrees into the application space.
374
269
 
375
 
SQLAlchemy commonly refers to an adjacency list relationship as a
376
 
**self-referential mapper**. In this example, we'll work with a single table
377
 
called ``nodes`` to represent a tree structure::
378
 
 
379
 
    nodes = Table('nodes', metadata,
380
 
        Column('id', Integer, primary_key=True),
381
 
        Column('parent_id', Integer, ForeignKey('nodes.id')),
382
 
        Column('data', String(50)),
383
 
        )
384
 
 
385
 
A graph such as the following::
 
270
In this example, we'll work with a single mapped
 
271
class called ``Node``, representing a tree structure::
 
272
 
 
273
    class Node(Base):
 
274
        __tablename__ = 'node'
 
275
        id = Column(Integer, primary_key=True)
 
276
        parent_id = Column(Integer, ForeignKey('node.id'))
 
277
        data = Column(String(50))
 
278
        children = relationship("Node")
 
279
 
 
280
With this structure, a graph such as the following::
386
281
 
387
282
    root --+---> child1
388
283
           +---> child2 --+--> subchild1
400
295
    5        3             subchild2
401
296
    6        1             child3
402
297
 
403
 
SQLAlchemy's :func:`.mapper` configuration for a self-referential one-to-many
404
 
relationship is exactly like a "normal" one-to-many relationship. When
405
 
SQLAlchemy encounters the foreign key relationship from ``nodes`` to
406
 
``nodes``, it assumes one-to-many unless told otherwise:
407
 
 
408
 
.. sourcecode:: python+sql
409
 
 
410
 
    # entity class
411
 
    class Node(object):
412
 
        pass
413
 
 
414
 
    mapper(Node, nodes, properties={
415
 
        'children': relationship(Node)
416
 
    })
417
 
 
418
 
To create a many-to-one relationship from child to parent, an extra indicator
419
 
of the "remote side" is added, which contains the
420
 
:class:`~sqlalchemy.schema.Column` object or objects indicating the remote
421
 
side of the relationship:
422
 
 
423
 
.. sourcecode:: python+sql
424
 
 
425
 
    mapper(Node, nodes, properties={
426
 
        'parent': relationship(Node, remote_side=[nodes.c.id])
427
 
    })
428
 
 
429
 
And the bi-directional version combines both:
430
 
 
431
 
.. sourcecode:: python+sql
432
 
 
433
 
    mapper(Node, nodes, properties={
434
 
        'children': relationship(Node, 
435
 
                            backref=backref('parent', remote_side=[nodes.c.id])
436
 
                        )
437
 
    })
438
 
 
439
 
For comparison, the declarative version typically uses the inline ``id`` 
440
 
:class:`.Column` attribute to declare remote_side (note the list form is optional
441
 
when the collection is only one column)::
442
 
 
443
 
    from sqlalchemy.ext.declarative import declarative_base
444
 
    Base = declarative_base()
445
 
 
446
 
    class Node(Base):
447
 
        __tablename__ = 'nodes'
448
 
        id = Column(Integer, primary_key=True)
449
 
        parent_id = Column(Integer, ForeignKey('nodes.id'))
 
298
The :func:`.relationship` configuration here works in the
 
299
same way as a "normal" one-to-many relationship, with the 
 
300
exception that the "direction", i.e. whether the relationship
 
301
is one-to-many or many-to-one, is assumed by default to
 
302
be one-to-many.   To establish the relationship as many-to-one,
 
303
an extra directive is added known as ``remote_side``, which
 
304
is a :class:`.Column` or collection of :class:`.Column` objects
 
305
that indicate those which should be considered to be "remote"::
 
306
 
 
307
    class Node(Base):
 
308
        __tablename__ = 'node'
 
309
        id = Column(Integer, primary_key=True)
 
310
        parent_id = Column(Integer, ForeignKey('node.id'))
 
311
        data = Column(String(50))
 
312
        parent = relationship("Node", remote_side=[id])
 
313
 
 
314
Where above, the ``id`` column is applied as the ``remote_side``
 
315
of the ``parent`` :func:`.relationship`, thus establishing
 
316
``parent_id`` as the "local" side, and the relationship
 
317
then behaves as a many-to-one.
 
318
 
 
319
As always, both directions can be combined into a bidirectional
 
320
relationship using the :func:`.backref` function::
 
321
 
 
322
    class Node(Base):
 
323
        __tablename__ = 'node'
 
324
        id = Column(Integer, primary_key=True)
 
325
        parent_id = Column(Integer, ForeignKey('node.id'))
450
326
        data = Column(String(50))
451
327
        children = relationship("Node", 
452
 
                        backref=backref('parent', remote_side=id)
453
 
                    )
 
328
                    backref=backref('parent', remote_side=[id])
 
329
                )
454
330
 
455
331
There are several examples included with SQLAlchemy illustrating
456
332
self-referential strategies; these include :ref:`examples_adjacencylist` and
459
335
Self-Referential Query Strategies
460
336
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
461
337
 
462
 
 
463
 
Querying self-referential structures is done in the same way as any other
464
 
query in SQLAlchemy, such as below, we query for any node whose ``data``
465
 
attribute stores the value ``child2``:
466
 
 
467
 
.. sourcecode:: python+sql
 
338
Querying of self-referential structures works like any other query::
468
339
 
469
340
    # get all nodes named 'child2'
470
341
    session.query(Node).filter(Node.data=='child2')
471
342
 
472
 
On the subject of joins, i.e. those described in `datamapping_joins`,
473
 
self-referential structures require the usage of aliases so that the same
474
 
table can be referenced multiple times within the FROM clause of the query.
475
 
Aliasing can be done either manually using the ``nodes``
476
 
:class:`~sqlalchemy.schema.Table` object as a source of aliases:
477
 
 
478
 
.. sourcecode:: python+sql
479
 
 
480
 
    # get all nodes named 'subchild1' with a parent named 'child2'
481
 
    nodealias = nodes.alias()
482
 
    {sql}session.query(Node).filter(Node.data=='subchild1').\
483
 
        filter(and_(Node.parent_id==nodealias.c.id, nodealias.c.data=='child2')).all()
484
 
    SELECT nodes.id AS nodes_id, nodes.parent_id AS nodes_parent_id, nodes.data AS nodes_data
485
 
    FROM nodes, nodes AS nodes_1
486
 
    WHERE nodes.data = ? AND nodes.parent_id = nodes_1.id AND nodes_1.data = ?
487
 
    ['subchild1', 'child2']
488
 
 
489
 
or automatically, using ``join()`` with ``aliased=True``:
490
 
 
491
 
.. sourcecode:: python+sql
492
 
 
493
 
    # get all nodes named 'subchild1' with a parent named 'child2'
494
 
    {sql}session.query(Node).filter(Node.data=='subchild1').\
495
 
        join('parent', aliased=True).filter(Node.data=='child2').all()
496
 
    SELECT nodes.id AS nodes_id, nodes.parent_id AS nodes_parent_id, nodes.data AS nodes_data
497
 
    FROM nodes JOIN nodes AS nodes_1 ON nodes_1.id = nodes.parent_id
498
 
    WHERE nodes.data = ? AND nodes_1.data = ?
499
 
    ['subchild1', 'child2']
500
 
 
501
 
To add criterion to multiple points along a longer join, use ``from_joinpoint=True``:
502
 
 
503
 
.. sourcecode:: python+sql
504
 
 
505
 
    # get all nodes named 'subchild1' with a parent named 'child2' and a grandparent 'root'
506
 
    {sql}session.query(Node).filter(Node.data=='subchild1').\
507
 
        join('parent', aliased=True).filter(Node.data=='child2').\
508
 
        join('parent', aliased=True, from_joinpoint=True).filter(Node.data=='root').all()
509
 
    SELECT nodes.id AS nodes_id, nodes.parent_id AS nodes_parent_id, nodes.data AS nodes_data
510
 
    FROM nodes JOIN nodes AS nodes_1 ON nodes_1.id = nodes.parent_id JOIN nodes AS nodes_2 ON nodes_2.id = nodes_1.parent_id
511
 
    WHERE nodes.data = ? AND nodes_1.data = ? AND nodes_2.data = ?
 
343
However extra care is needed when attempting to join along 
 
344
the foreign key from one level of the tree to the next.  In SQL,
 
345
a join from a table to itself requires that at least one side of the
 
346
expression be "aliased" so that it can be unambiguously referred to.
 
347
 
 
348
Recall from :ref:`ormtutorial_aliases` in the ORM tutorial that the
 
349
:class:`.orm.aliased` construct is normally used to provide an "alias" of 
 
350
an ORM entity.  Joining from ``Node`` to itself using this technique
 
351
looks like:
 
352
 
 
353
.. sourcecode:: python+sql
 
354
 
 
355
    from sqlalchemy.orm import aliased
 
356
 
 
357
    nodealias = aliased(Node)
 
358
    {sql}session.query(Node).filter(Node.data=='subchild1').\
 
359
                    join(nodealias, Node.parent).\
 
360
                    filter(nodealias.data=="child2").\
 
361
                    all()
 
362
    SELECT node.id AS node_id, 
 
363
            node.parent_id AS node_parent_id, 
 
364
            node.data AS node_data
 
365
    FROM node JOIN node AS node_1
 
366
        ON node.parent_id = node_1.id 
 
367
    WHERE node.data = ? 
 
368
        AND node_1.data = ?
 
369
    ['subchild1', 'child2']
 
370
 
 
371
:meth:`.Query.join` also includes a feature known as ``aliased=True`` that 
 
372
can shorten the verbosity self-referential joins, at the expense
 
373
of query flexibility.  This feature
 
374
performs a similar "aliasing" step to that above, without the need for an 
 
375
explicit entity.   Calls to :meth:`.Query.filter` and similar subsequent to 
 
376
the aliased join will **adapt** the ``Node`` entity to be that of the alias:
 
377
 
 
378
.. sourcecode:: python+sql
 
379
 
 
380
    {sql}session.query(Node).filter(Node.data=='subchild1').\
 
381
            join(Node.parent, aliased=True).\
 
382
            filter(Node.data=='child2').\
 
383
            all()
 
384
    SELECT node.id AS node_id, 
 
385
            node.parent_id AS node_parent_id, 
 
386
            node.data AS node_data
 
387
    FROM node 
 
388
        JOIN node AS node_1 ON node_1.id = node.parent_id
 
389
    WHERE node.data = ? AND node_1.data = ?
 
390
    ['subchild1', 'child2']
 
391
 
 
392
To add criterion to multiple points along a longer join, add ``from_joinpoint=True``
 
393
to the additional :meth:`~.Query.join` calls:
 
394
 
 
395
.. sourcecode:: python+sql
 
396
 
 
397
    # get all nodes named 'subchild1' with a 
 
398
    # parent named 'child2' and a grandparent 'root'
 
399
    {sql}session.query(Node).\
 
400
            filter(Node.data=='subchild1').\
 
401
            join(Node.parent, aliased=True).\
 
402
            filter(Node.data=='child2').\
 
403
            join(Node.parent, aliased=True, from_joinpoint=True).\
 
404
            filter(Node.data=='root').\
 
405
            all()
 
406
    SELECT node.id AS node_id, 
 
407
            node.parent_id AS node_parent_id, 
 
408
            node.data AS node_data
 
409
    FROM node 
 
410
        JOIN node AS node_1 ON node_1.id = node.parent_id 
 
411
        JOIN node AS node_2 ON node_2.id = node_1.parent_id
 
412
    WHERE node.data = ? 
 
413
        AND node_1.data = ? 
 
414
        AND node_2.data = ?
512
415
    ['subchild1', 'child2', 'root']
513
416
 
514
 
Configuring Eager Loading
515
 
~~~~~~~~~~~~~~~~~~~~~~~~~~
 
417
:meth:`.Query.reset_joinpoint` will also remove the "aliasing" from filtering 
 
418
calls::
 
419
 
 
420
    session.query(Node).\
 
421
            join(Node.children, aliased=True).\
 
422
            filter(Node.data == 'foo').\
 
423
            reset_joinpoint().\
 
424
            filter(Node.data == 'bar')
 
425
 
 
426
For an example of using ``aliased=True`` to arbitrarily join along a chain of self-referential
 
427
nodes, see :ref:`examples_xmlpersistence`.
 
428
 
 
429
Configuring Self-Referential Eager Loading
 
430
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
516
431
 
517
432
Eager loading of relationships occurs using joins or outerjoins from parent to
518
433
child table during a normal query operation, such that the parent and its
519
 
child collection can be populated from a single SQL statement, or a second
520
 
statement for all collections at once. SQLAlchemy's joined and subquery eager
521
 
loading uses aliased tables in all cases when joining to related items, so it
522
 
is compatible with self-referential joining. However, to use eager loading
523
 
with a self-referential relationship, SQLAlchemy needs to be told how many
524
 
levels deep it should join; otherwise the eager load will not take place. This
525
 
depth setting is configured via ``join_depth``:
 
434
immediate child collection or reference can be populated from a single SQL
 
435
statement, or a second statement for all immediate child collections.
 
436
SQLAlchemy's joined and subquery eager loading use aliased tables in all cases
 
437
when joining to related items, so are compatible with self-referential
 
438
joining. However, to use eager loading with a self-referential relationship,
 
439
SQLAlchemy needs to be told how many levels deep it should join and/or query;
 
440
otherwise the eager load will not take place at all. This depth setting is
 
441
configured via ``join_depth``:
526
442
 
527
443
.. sourcecode:: python+sql
528
444
 
529
 
    mapper(Node, nodes, properties={
530
 
        'children': relationship(Node, lazy='joined', join_depth=2)
531
 
    })
 
445
    class Node(Base):
 
446
        __tablename__ = 'node'
 
447
        id = Column(Integer, primary_key=True)
 
448
        parent_id = Column(Integer, ForeignKey('node.id'))
 
449
        data = Column(String(50))
 
450
        children = relationship("Node",
 
451
                        lazy="joined",
 
452
                        join_depth=2)
532
453
 
533
454
    {sql}session.query(Node).all()
534
 
    SELECT nodes_1.id AS nodes_1_id, nodes_1.parent_id AS nodes_1_parent_id, nodes_1.data AS nodes_1_data, nodes_2.id AS nodes_2_id, nodes_2.parent_id AS nodes_2_parent_id, nodes_2.data AS nodes_2_data, nodes.id AS nodes_id, nodes.parent_id AS nodes_parent_id, nodes.data AS nodes_data
535
 
    FROM nodes LEFT OUTER JOIN nodes AS nodes_2 ON nodes.id = nodes_2.parent_id LEFT OUTER JOIN nodes AS nodes_1 ON nodes_2.id = nodes_1.parent_id
 
455
    SELECT node_1.id AS node_1_id, 
 
456
            node_1.parent_id AS node_1_parent_id, 
 
457
            node_1.data AS node_1_data, 
 
458
            node_2.id AS node_2_id, 
 
459
            node_2.parent_id AS node_2_parent_id, 
 
460
            node_2.data AS node_2_data, 
 
461
            node.id AS node_id, 
 
462
            node.parent_id AS node_parent_id, 
 
463
            node.data AS node_data
 
464
    FROM node 
 
465
        LEFT OUTER JOIN node AS node_2 
 
466
            ON node.id = node_2.parent_id 
 
467
        LEFT OUTER JOIN node AS node_1 
 
468
            ON node_2.id = node_1.parent_id
536
469
    []
537
470
 
538
 
Linking relationships with Backref
 
471
.. _relationships_backref:
 
472
 
 
473
Linking Relationships with Backref
539
474
----------------------------------
540
475
 
541
476
The ``backref`` keyword argument was first introduced in :ref:`ormtutorial_toplevel`, and has been
593
528
 
594
529
Above, we add a ``.user`` relationship to ``Address`` explicitly.  On 
595
530
both relationships, the ``back_populates`` directive tells each relationship 
596
 
about the other one, indicating that they should establish "bi-directional"
 
531
about the other one, indicating that they should establish "bidirectional"
597
532
behavior between each other.   The primary effect of this configuration
598
533
is that the relationship adds event handlers to both attributes 
599
534
which have the behavior of "when an append or set event occurs here, set ourselves
1031
966
                    addresses_table.c.city=='New York')),
1032
967
    })
1033
968
 
 
969
.. _post_update:
1034
970
 
1035
971
Rows that point to themselves / Mutually Dependent Rows
1036
972
-------------------------------------------------------