1.. _inheritance_loading_toplevel:
2
3.. currentmodule:: sqlalchemy.orm
4
5Loading Inheritance Hierarchies
6===============================
7
8When classes are mapped in inheritance hierarchies using the "joined",
9"single", or "concrete" table inheritance styles as described at
10:ref:`inheritance_toplevel`, the usual behavior is that a query for a
11particular base class will also yield objects corresponding to subclasses
12as well.   When a single query is capable of returning a result with
13a different class or subclasses per result row, we use the term
14"polymorphic loading".
15
16Within the realm of polymorphic loading, specifically with joined and single
17table inheritance, there is an additional problem of which subclass attributes
18are to be queried up front, and which are to be loaded later. When an attribute
19of a particular subclass is queried up front, we can use it in our query as
20something to filter on, and it also will be loaded when we get our objects
21back.   If it's not queried up front, it gets loaded later when we first need
22to access it.   Basic control of this behavior is provided using the
23:func:`_orm.with_polymorphic` function, as well as two variants, the mapper
24configuration :paramref:`.mapper.with_polymorphic` in conjunction with
25the :paramref:`.mapper.polymorphic_load` option, and the :class:`_query.Query`
26-level :meth:`_query.Query.with_polymorphic` method.    The "with_polymorphic" family
27each provide a means of specifying which specific subclasses of a particular
28base class should be included within a query, which implies what columns and
29tables will be available in the SELECT.
30
31.. _with_polymorphic:
32
33Using with_polymorphic
34----------------------
35
36For the following sections, assume the ``Employee`` / ``Engineer`` / ``Manager``
37examples introduced in :ref:`inheritance_toplevel`.
38
39Normally, when a :class:`_query.Query` specifies the base class of an
40inheritance hierarchy, only the columns that are local to that base
41class are queried::
42
43    session.query(Employee).all()
44
45Above, for both single and joined table inheritance, only the columns
46local to ``Employee`` will be present in the SELECT.   We may get back
47instances of ``Engineer`` or ``Manager``, however they will not have the
48additional attributes loaded until we first access them, at which point a
49lazy load is emitted.
50
51Similarly, if we wanted to refer to columns mapped
52to ``Engineer`` or ``Manager`` in our query that's against ``Employee``,
53these columns aren't available directly in either the single or joined table
54inheritance case, since the ``Employee`` entity does not refer to these columns
55(note that for single-table inheritance, this is common if Declarative is used,
56but not for a classical mapping).
57
58To solve both of these issues, the :func:`_orm.with_polymorphic` function
59provides a special :class:`.AliasedClass` that represents a range of
60columns across subclasses. This object can be used in a :class:`_query.Query`
61like any other alias.  When queried, it represents all the columns present in
62the classes given::
63
64    from sqlalchemy.orm import with_polymorphic
65
66    eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])
67
68    query = session.query(eng_plus_manager)
69
70If the above mapping were using joined table inheritance, the SELECT
71statement for the above would be:
72
73.. sourcecode:: python+sql
74
75    query.all()
76    {opensql}
77    SELECT
78        employee.id AS employee_id,
79        engineer.id AS engineer_id,
80        manager.id AS manager_id,
81        employee.name AS employee_name,
82        employee.type AS employee_type,
83        engineer.engineer_info AS engineer_engineer_info,
84        manager.manager_data AS manager_manager_data
85    FROM
86        employee
87        LEFT OUTER JOIN engineer ON employee.id = engineer.id
88        LEFT OUTER JOIN manager ON employee.id = manager.id
89    []
90
91Where above, the additional tables / columns for "engineer" and "manager" are
92included.  Similar behavior occurs in the case of single table inheritance.
93
94:func:`_orm.with_polymorphic` accepts a single class or
95mapper, a list of classes/mappers, or the string ``'*'`` to indicate all
96subclasses:
97
98.. sourcecode:: python+sql
99
100    # include columns for Engineer
101    entity = with_polymorphic(Employee, Engineer)
102
103    # include columns for Engineer, Manager
104    entity = with_polymorphic(Employee, [Engineer, Manager])
105
106    # include columns for all mapped subclasses
107    entity = with_polymorphic(Employee, '*')
108
109.. tip::
110
111    It's important to note that :func:`_orm.with_polymorphic` only affects the
112    **columns that are included in fetched rows**, and not the **types of
113    objects returned**. A call to ``with_polymorphic(Employee, [Manager])``
114    will refer to rows that contain all types of ``Employee`` objects,
115    including not only ``Manager`` objects, but also ``Engineer`` objects as
116    these are subclasses of ``Employee``, as well as ``Employee`` instances if
117    these are present in the database. The effect of using
118    ``with_polymorphic(Employee, [Manager])`` would only provide the behavior
119    that additional columns specific to ``Manager`` will be eagerly loaded in
120    result rows, and as described below in
121    :ref:`with_polymorphic_subclass_attributes` also be available for use
122    within the WHERE clause of the SELECT statement.
123
124Using aliasing with with_polymorphic
125~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
126
127The :func:`_orm.with_polymorphic` function also provides "aliasing" of the
128polymorphic selectable itself, meaning, two different :func:`_orm.with_polymorphic`
129entities, referring to the same class hierarchy, can be used together.  This
130is available using the :paramref:`.orm.with_polymorphic.aliased` flag.
131For a polymorphic selectable that is across multiple tables, the default behavior
132is to wrap the selectable into a subquery.  Below we emit a query that will
133select for "employee or manager" paired with "employee or engineer" on employees
134with the same name:
135
136.. sourcecode:: python+sql
137
138    engineer_employee = with_polymorphic(
139        Employee, [Engineer], aliased=True)
140    manager_employee = with_polymorphic(
141        Employee, [Manager], aliased=True)
142
143    q = s.query(engineer_employee, manager_employee).\
144        join(
145            manager_employee,
146            and_(
147                engineer_employee.id > manager_employee.id,
148                engineer_employee.name == manager_employee.name
149            )
150    )
151    q.all()
152    {opensql}
153    SELECT
154        anon_1.employee_id AS anon_1_employee_id,
155        anon_1.employee_name AS anon_1_employee_name,
156        anon_1.employee_type AS anon_1_employee_type,
157        anon_1.engineer_id AS anon_1_engineer_id,
158        anon_1.engineer_engineer_name AS anon_1_engineer_engineer_name,
159        anon_2.employee_id AS anon_2_employee_id,
160        anon_2.employee_name AS anon_2_employee_name,
161        anon_2.employee_type AS anon_2_employee_type,
162        anon_2.manager_id AS anon_2_manager_id,
163        anon_2.manager_manager_name AS anon_2_manager_manager_name
164    FROM (
165        SELECT
166            employee.id AS employee_id,
167            employee.name AS employee_name,
168            employee.type AS employee_type,
169            engineer.id AS engineer_id,
170            engineer.engineer_name AS engineer_engineer_name
171        FROM employee
172        LEFT OUTER JOIN engineer ON employee.id = engineer.id
173    ) AS anon_1
174    JOIN (
175        SELECT
176            employee.id AS employee_id,
177            employee.name AS employee_name,
178            employee.type AS employee_type,
179            manager.id AS manager_id,
180             manager.manager_name AS manager_manager_name
181        FROM employee
182        LEFT OUTER JOIN manager ON employee.id = manager.id
183    ) AS anon_2
184    ON anon_1.employee_id > anon_2.employee_id
185    AND anon_1.employee_name = anon_2.employee_name
186
187The creation of subqueries above is very verbose.  While it creates the best
188encapsulation of the two distinct queries, it may be inefficient.
189:func:`_orm.with_polymorphic` includes an additional flag to help with this
190situation, :paramref:`.orm.with_polymorphic.flat`, which will "flatten" the
191subquery / join combination into straight joins, applying aliasing to the
192individual tables instead.   Setting :paramref:`.orm.with_polymorphic.flat`
193implies :paramref:`.orm.with_polymorphic.aliased`, so only one flag
194is necessary:
195
196.. sourcecode:: python+sql
197
198    engineer_employee = with_polymorphic(
199        Employee, [Engineer], flat=True)
200    manager_employee = with_polymorphic(
201        Employee, [Manager], flat=True)
202
203    q = s.query(engineer_employee, manager_employee).\
204        join(
205            manager_employee,
206            and_(
207                engineer_employee.id > manager_employee.id,
208                engineer_employee.name == manager_employee.name
209            )
210    )
211    q.all()
212    {opensql}
213    SELECT
214        employee_1.id AS employee_1_id,
215        employee_1.name AS employee_1_name,
216        employee_1.type AS employee_1_type,
217        engineer_1.id AS engineer_1_id,
218        engineer_1.engineer_name AS engineer_1_engineer_name,
219        employee_2.id AS employee_2_id,
220        employee_2.name AS employee_2_name,
221        employee_2.type AS employee_2_type,
222        manager_1.id AS manager_1_id,
223        manager_1.manager_name AS manager_1_manager_name
224    FROM employee AS employee_1
225    LEFT OUTER JOIN engineer AS engineer_1
226    ON employee_1.id = engineer_1.id
227    JOIN (
228        employee AS employee_2
229        LEFT OUTER JOIN manager AS manager_1
230        ON employee_2.id = manager_1.id
231    )
232    ON employee_1.id > employee_2.id
233    AND employee_1.name = employee_2.name
234
235Note above, when using :paramref:`.orm.with_polymorphic.flat`, it is often the
236case when used in conjunction with joined table inheritance that we get a
237right-nested JOIN in our statement.   Some older databases, in particular older
238versions of SQLite, may have a problem with this syntax, although virtually all
239modern database versions now support this syntax.
240
241.. note::
242
243    The :paramref:`.orm.with_polymorphic.flat` flag only applies to the use
244    of :paramref:`.with_polymorphic` with **joined table inheritance** and when
245    the :paramref:`.with_polymorphic.selectable` argument is **not** used.
246
247.. _with_polymorphic_subclass_attributes:
248
249Referring to Specific Subclass Attributes
250~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
251
252The entity returned by :func:`_orm.with_polymorphic` is an :class:`.AliasedClass`
253object, which can be used in a :class:`_query.Query` like any other alias, including
254named attributes for those attributes on the ``Employee`` class.   In our
255previous example, ``eng_plus_manager`` becomes the entity that we use to refer to the
256three-way outer join above.  It also includes namespaces for each class named
257in the list of classes, so that attributes specific to those subclasses can be
258called upon as well.   The following example illustrates calling upon attributes
259specific to ``Engineer`` as well as ``Manager`` in terms of ``eng_plus_manager``::
260
261    eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])
262    query = session.query(eng_plus_manager).filter(
263                    or_(
264                        eng_plus_manager.Engineer.engineer_info=='x',
265                        eng_plus_manager.Manager.manager_data=='y'
266                    )
267                )
268
269A query as above would generate SQL resembling the following:
270
271.. sourcecode:: python+sql
272
273    query.all()
274    {opensql}
275    SELECT
276        employee.id AS employee_id,
277        engineer.id AS engineer_id,
278        manager.id AS manager_id,
279        employee.name AS employee_name,
280        employee.type AS employee_type,
281        engineer.engineer_info AS engineer_engineer_info,
282        manager.manager_data AS manager_manager_data
283    FROM
284        employee
285        LEFT OUTER JOIN engineer ON employee.id = engineer.id
286        LEFT OUTER JOIN manager ON employee.id = manager.id
287    WHERE
288      engineer.engineer_info=? OR
289      manager.manager_data=?
290    ['x', 'y']
291
292
293
294.. _with_polymorphic_mapper_config:
295
296Setting with_polymorphic at mapper configuration time
297~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
298
299The :func:`_orm.with_polymorphic` function serves the purpose of allowing
300"eager" loading of attributes from subclass tables, as well as the ability
301to refer to the attributes from subclass tables at query time.   Historically,
302the "eager loading" of columns has been the more important part of the
303equation.   So just as eager loading for relationships can be specified
304as a configurational option, the :paramref:`.mapper.with_polymorphic`
305configuration parameter allows an entity to use a polymorphic load by
306default.  We can add the parameter to our ``Employee`` mapping
307first introduced at :ref:`joined_inheritance`::
308
309    class Employee(Base):
310        __tablename__ = 'employee'
311        id = Column(Integer, primary_key=True)
312        name = Column(String(50))
313        type = Column(String(50))
314
315        __mapper_args__ = {
316            'polymorphic_identity':'employee',
317            'polymorphic_on':type,
318            'with_polymorphic': '*'
319        }
320
321Above is a common setting for :paramref:`.mapper.with_polymorphic`,
322which is to indicate an asterisk to load all subclass columns.   In the
323case of joined table inheritance, this option
324should be used sparingly, as it implies that the mapping will always emit
325a (often large) series of LEFT OUTER JOIN to many tables, which is not
326efficient from a SQL perspective.   For single table inheritance, specifying the
327asterisk is often a good idea as the load is still against a single table only,
328but an additional lazy load of subclass-mapped columns will be prevented.
329
330Using :func:`_orm.with_polymorphic` or :meth:`_query.Query.with_polymorphic`
331will override the mapper-level :paramref:`.mapper.with_polymorphic` setting.
332
333The :paramref:`.mapper.with_polymorphic` option also accepts a list of
334classes just like :func:`_orm.with_polymorphic` to polymorphically load among
335a subset of classes.  However, when using Declarative, providing classes
336to this list is not directly possible as the subclasses we'd like to add
337are not available yet.   Instead, we can specify on each subclass
338that they should individually participate in polymorphic loading by
339default using the :paramref:`.mapper.polymorphic_load` parameter::
340
341    class Engineer(Employee):
342        __tablename__ = 'engineer'
343        id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
344        engineer_info = Column(String(50))
345        __mapper_args__ = {
346            'polymorphic_identity':'engineer',
347            'polymorphic_load': 'inline'
348        }
349
350    class Manager(Employee):
351        __tablename__ = 'manager'
352        id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
353        manager_data = Column(String(50))
354        __mapper_args__ = {
355            'polymorphic_identity':'manager',
356            'polymorphic_load': 'inline'
357        }
358
359Setting the :paramref:`.mapper.polymorphic_load` parameter to the value
360``"inline"`` means that the ``Engineer`` and ``Manager`` classes above
361are part of the "polymorphic load" of the base ``Employee`` class by default,
362exactly as though they had been appended to the
363:paramref:`.mapper.with_polymorphic` list of classes.
364
365Setting with_polymorphic against a query
366~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
367
368The :func:`_orm.with_polymorphic` function evolved from a query-level
369method :meth:`_query.Query.with_polymorphic`.  This method has the same purpose
370as :func:`_orm.with_polymorphic`, except is not as
371flexible in its usage patterns in that it only applies to the first entity
372of the :class:`_query.Query`.   It then takes effect for all occurrences of
373that entity, so that the entity (and its subclasses) can be referred to
374directly, rather than using an alias object.  For simple cases it might be
375considered to be more succinct::
376
377    session.query(Employee).\
378        with_polymorphic([Engineer, Manager]).\
379        filter(
380            or_(
381                Engineer.engineer_info=='w',
382                Manager.manager_data=='q'
383            )
384        )
385
386The :meth:`_query.Query.with_polymorphic` method has a more complicated job
387than the :func:`_orm.with_polymorphic` function, as it needs to correctly
388transform entities like ``Engineer`` and ``Manager`` appropriately, but
389not interfere with other entities.  If its flexibility is lacking, switch
390to using :func:`_orm.with_polymorphic`.
391
392.. _polymorphic_selectin:
393
394Polymorphic Selectin Loading
395----------------------------
396
397An alternative to using the :func:`_orm.with_polymorphic` family of
398functions to "eagerly" load the additional subclasses on an inheritance
399mapping, primarily when using joined table inheritance, is to use polymorphic
400"selectin" loading.   This is an eager loading
401feature which works similarly to the :ref:`selectin_eager_loading` feature
402of relationship loading.   Given our example mapping, we can instruct
403a load of ``Employee`` to emit an extra SELECT per subclass by using
404the :func:`_orm.selectin_polymorphic` loader option::
405
406    from sqlalchemy.orm import selectin_polymorphic
407
408    query = session.query(Employee).options(
409        selectin_polymorphic(Employee, [Manager, Engineer])
410    )
411
412When the above query is run, two additional SELECT statements will
413be emitted:
414
415.. sourcecode:: python+sql
416
417    {opensql}query.all()
418    SELECT
419        employee.id AS employee_id,
420        employee.name AS employee_name,
421        employee.type AS employee_type
422    FROM employee
423    ()
424
425    SELECT
426        engineer.id AS engineer_id,
427        employee.id AS employee_id,
428        employee.type AS employee_type,
429        engineer.engineer_name AS engineer_engineer_name
430    FROM employee JOIN engineer ON employee.id = engineer.id
431    WHERE employee.id IN (?, ?) ORDER BY employee.id
432    (1, 2)
433
434    SELECT
435        manager.id AS manager_id,
436        employee.id AS employee_id,
437        employee.type AS employee_type,
438        manager.manager_name AS manager_manager_name
439    FROM employee JOIN manager ON employee.id = manager.id
440    WHERE employee.id IN (?) ORDER BY employee.id
441    (3,)
442
443We can similarly establish the above style of loading to take place
444by default by specifying the :paramref:`.mapper.polymorphic_load` parameter,
445using the value ``"selectin"`` on a per-subclass basis::
446
447    class Employee(Base):
448        __tablename__ = 'employee'
449        id = Column(Integer, primary_key=True)
450        name = Column(String(50))
451        type = Column(String(50))
452
453        __mapper_args__ = {
454            'polymorphic_identity': 'employee',
455            'polymorphic_on': type
456        }
457
458    class Engineer(Employee):
459        __tablename__ = 'engineer'
460        id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
461        engineer_name = Column(String(30))
462
463        __mapper_args__ = {
464            'polymorphic_load': 'selectin',
465            'polymorphic_identity': 'engineer',
466        }
467
468    class Manager(Employee):
469        __tablename__ = 'manager'
470        id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
471        manager_name = Column(String(30))
472
473        __mapper_args__ = {
474            'polymorphic_load': 'selectin',
475            'polymorphic_identity': 'manager',
476        }
477
478
479Unlike when using :func:`_orm.with_polymorphic`, when using the
480:func:`_orm.selectin_polymorphic` style of loading, we do **not** have the
481ability to refer to the ``Engineer`` or ``Manager`` entities within our main
482query as filter, order by, or other criteria, as these entities are not present
483in the initial query that is used to locate results.   However, we can apply
484loader options that apply towards ``Engineer`` or ``Manager``, which will take
485effect when the secondary SELECT is emitted.  Below we assume ``Manager`` has
486an additional relationship ``Manager.paperwork``, that we'd like to eagerly
487load as well.  We can use any type of eager loading, such as joined eager
488loading via the :func:`_orm.joinedload` function::
489
490    from sqlalchemy.orm import joinedload
491    from sqlalchemy.orm import selectin_polymorphic
492
493    query = session.query(Employee).options(
494        selectin_polymorphic(Employee, [Manager, Engineer]),
495        joinedload(Manager.paperwork)
496    )
497
498Using the query above, we get three SELECT statements emitted, however
499the one against ``Manager`` will be:
500
501.. sourcecode:: sql
502
503    SELECT
504        manager.id AS manager_id,
505        employee.id AS employee_id,
506        employee.type AS employee_type,
507        manager.manager_name AS manager_manager_name,
508        paperwork_1.id AS paperwork_1_id,
509        paperwork_1.manager_id AS paperwork_1_manager_id,
510        paperwork_1.data AS paperwork_1_data
511    FROM employee JOIN manager ON employee.id = manager.id
512    LEFT OUTER JOIN paperwork AS paperwork_1
513    ON manager.id = paperwork_1.manager_id
514    WHERE employee.id IN (?) ORDER BY employee.id
515    (3,)
516
517Note that selectin polymorphic loading has similar caveats as that of
518selectin relationship loading; for entities that make use of a composite
519primary key, the database in use must support tuples with "IN", currently
520known to work with MySQL and PostgreSQL.
521
522.. versionadded:: 1.2
523
524.. warning::  The selectin polymorphic loading feature should be considered
525   as **experimental** within early releases of the 1.2 series.
526
527.. _polymorphic_selectin_and_withpoly:
528
529Combining selectin and with_polymorphic
530~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
531
532.. note:: works as of 1.2.0b3
533
534With careful planning, selectin loading can be applied against a hierarchy
535that itself uses "with_polymorphic".  A particular use case is that of
536using selectin loading to load a joined-inheritance subtable, which then
537uses "with_polymorphic" to refer to further sub-classes, which may be
538joined- or single-table inheritance.  If we added a class ``VicePresident`` that
539extends ``Manager`` using single-table inheritance, we could ensure that
540a load of ``Manager`` also fully loads ``VicePresident`` subtypes at the same time::
541
542    # use "Employee" example from the enclosing section
543
544    class Manager(Employee):
545        __tablename__ = 'manager'
546        id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
547        manager_name = Column(String(30))
548
549        __mapper_args__ = {
550            'polymorphic_load': 'selectin',
551            'polymorphic_identity': 'manager',
552        }
553
554    class VicePresident(Manager):
555        vp_info = Column(String(30))
556
557        __mapper_args__ = {
558            "polymorphic_load": "inline",
559            "polymorphic_identity": "vp"
560        }
561
562
563Above, we add a ``vp_info`` column to the ``manager`` table, local to the
564``VicePresident`` subclass.   This subclass is linked to the polymorphic
565identity ``"vp"`` which refers to rows which have this data.     By setting the
566load style to "inline", it means that a load of ``Manager`` objects will also
567ensure that the ``vp_info`` column is queried for in the same SELECT statement.
568A query against ``Employee`` that encounters a ``Manager`` row would emit
569similarly to the following:
570
571.. sourcecode:: sql
572
573    SELECT employee.id AS employee_id, employee.name AS employee_name,
574           employee.type AS employee_type
575    FROM employee
576    )
577
578    SELECT manager.id AS manager_id, employee.id AS employee_id,
579           employee.type AS employee_type,
580           manager.manager_name AS manager_manager_name,
581           manager.vp_info AS manager_vp_info
582    FROM employee JOIN manager ON employee.id = manager.id
583    WHERE employee.id IN (?) ORDER BY employee.id
584    (1,)
585
586Combining "selectin" polymorphic loading with query-time
587:func:`_orm.with_polymorphic` usage is also possible (though this is very
588outer-space stuff!); assuming the above mappings had no ``polymorphic_load``
589set up, we could get the same result as follows::
590
591    from sqlalchemy.orm import with_polymorphic, selectin_polymorphic
592
593    manager_poly = with_polymorphic(Manager, [VicePresident])
594
595    s.query(Employee).options(
596        selectin_polymorphic(Employee, [manager_poly])).all()
597
598.. _inheritance_of_type:
599
600Referring to specific subtypes on relationships
601-----------------------------------------------
602
603Mapped attributes which correspond to a :func:`_orm.relationship` are used
604in querying in order to refer to the linkage between two mappings.  Common
605uses for this are to refer to a :func:`_orm.relationship` in :meth:`_query.Query.join`
606as well as in loader options like :func:`_orm.joinedload`.   When using
607:func:`_orm.relationship` where the target class is an inheritance hierarchy,
608the API allows that the join, eager load, or other linkage should target a specific
609subclass, alias, or :func:`_orm.with_polymorphic` alias, of that class hierarchy,
610rather than the class directly targeted by the :func:`_orm.relationship`.
611
612The :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type` method allows the
613construction of joins along :func:`~sqlalchemy.orm.relationship` paths while
614narrowing the criterion to specific derived aliases or subclasses. Suppose the
615``employees`` table represents a collection of employees which are associated
616with a ``Company`` object. We'll add a ``company_id`` column to the
617``employees`` table and a new table ``companies``:
618
619.. sourcecode:: python
620
621    class Company(Base):
622        __tablename__ = 'company'
623        id = Column(Integer, primary_key=True)
624        name = Column(String(50))
625        employees = relationship("Employee",
626                        backref='company')
627
628    class Employee(Base):
629        __tablename__ = 'employee'
630        id = Column(Integer, primary_key=True)
631        type = Column(String(20))
632        company_id = Column(Integer, ForeignKey('company.id'))
633        __mapper_args__ = {
634            'polymorphic_on':type,
635            'polymorphic_identity':'employee',
636        }
637
638    class Engineer(Employee):
639        __tablename__ = 'engineer'
640        id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
641        engineer_info = Column(String(50))
642        __mapper_args__ = {'polymorphic_identity':'engineer'}
643
644    class Manager(Employee):
645        __tablename__ = 'manager'
646        id = Column(Integer, ForeignKey('employee.id'), primary_key=True)
647        manager_data = Column(String(50))
648        __mapper_args__ = {'polymorphic_identity':'manager'}
649
650When querying from ``Company`` onto the ``Employee`` relationship, the
651:meth:`_query.Query.join` method as well as operators like :meth:`.PropComparator.any`
652and :meth:`.PropComparator.has` will create
653a join from ``company`` to ``employee``, without including ``engineer`` or
654``manager`` in the mix. If we wish to have criterion which is specifically
655against the ``Engineer`` class, we can tell those methods to join or subquery
656against the set of columns representing the subclass using the
657:meth:`~.orm.interfaces.PropComparator.of_type` operator::
658
659    session.query(Company).\
660        join(Company.employees.of_type(Engineer)).\
661        filter(Engineer.engineer_info=='someinfo')
662
663Similarly, to join from ``Company`` to the polymorphic entity that includes both
664``Engineer`` and ``Manager`` columns::
665
666    manager_and_engineer = with_polymorphic(
667                                Employee, [Manager, Engineer])
668
669    session.query(Company).\
670        join(Company.employees.of_type(manager_and_engineer)).\
671        filter(
672            or_(
673                manager_and_engineer.Engineer.engineer_info == 'someinfo',
674                manager_and_engineer.Manager.manager_data == 'somedata'
675            )
676        )
677
678The :meth:`.PropComparator.any` and :meth:`.PropComparator.has` operators also
679can be used with :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type`,
680such as when the embedded criterion is in terms of a subclass::
681
682    session.query(Company).\
683            filter(
684                Company.employees.of_type(Engineer).
685                    any(Engineer.engineer_info=='someinfo')
686                ).all()
687
688.. _eagerloading_polymorphic_subtypes:
689
690Eager Loading of Specific or Polymorphic Subtypes
691~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
692
693The :func:`_orm.joinedload`, :func:`.subqueryload`, :func:`.contains_eager` and
694other eagerloader options support
695paths which make use of :func:`~.PropComparator.of_type`.
696Below, we load ``Company`` rows while eagerly loading related ``Engineer``
697objects, querying the ``employee`` and ``engineer`` tables simultaneously::
698
699    session.query(Company).\
700        options(
701            subqueryload(Company.employees.of_type(Engineer)).
702            subqueryload(Engineer.machines)
703            )
704        )
705
706As is the case with :meth:`_query.Query.join`, :meth:`~.PropComparator.of_type`
707can be used to combine eager loading and :func:`_orm.with_polymorphic`,
708so that all sub-attributes of all referenced subtypes
709can be loaded::
710
711    manager_and_engineer = with_polymorphic(
712                                Employee, [Manager, Engineer],
713                                flat=True)
714
715    session.query(Company).\
716        options(
717            joinedload(
718                Company.employees.of_type(manager_and_engineer)
719            )
720        )
721
722.. note::
723
724    When using :func:`.with_polymorphic` in conjunction with
725    :func:`_orm.joinedload`, the :func:`.with_polymorphic` object must be against
726    an "aliased" object, that is an instance of :class:`_expression.Alias`, so that the
727    polymorphic selectable is aliased (an informative error message is raised
728    otherwise).
729
730    The typical way to do this is to include the
731    :paramref:`.with_polymorphic.aliased` or :paramref:`.flat` flag, which will
732    apply this aliasing automatically.  However, if the
733    :paramref:`.with_polymorphic.selectable` argument is being used to pass an
734    object that is already an :class:`_expression.Alias` object then this flag should
735    **not** be set.  The "flat" option implies the "aliased" option and is an
736    alternate form of aliasing against join objects that produces fewer
737    subqueries.
738
739Once :meth:`~.PropComparator.of_type` is the target of the eager load,
740that's the entity we would use for subsequent chaining, not the original class
741or derived class.  If we wanted to further eager load a collection on the
742eager-loaded ``Engineer`` class, we access this class from the namespace of the
743:func:`_orm.with_polymorphic` object::
744
745    session.query(Company).\
746        options(
747            joinedload(Company.employees.of_type(manager_and_engineer)).\
748            subqueryload(manager_and_engineer.Engineer.computers)
749            )
750        )
751
752.. _loading_joined_inheritance:
753
754Loading objects with joined table inheritance
755---------------------------------------------
756
757When using joined table inheritance, if we query for a specific subclass
758that represents a JOIN of two tables such as our ``Engineer`` example
759from the inheritance section, the SQL emitted is a join::
760
761    session.query(Engineer).all()
762
763The above query will emit SQL like:
764
765.. sourcecode:: python+sql
766
767    {opensql}
768    SELECT employee.id AS employee_id,
769        employee.name AS employee_name, employee.type AS employee_type,
770        engineer.name AS engineer_name
771    FROM employee JOIN engineer
772    ON employee.id = engineer.id
773
774We will then get a collection of ``Engineer`` objects back, which will
775contain all columns from ``employee`` and ``engineer`` loaded.
776
777However, when emitting a :class:`_query.Query` against a base class, the behavior
778is to load only from the base table::
779
780    session.query(Employee).all()
781
782Above, the default behavior would be to SELECT only from the ``employee``
783table and not from any "sub" tables (``engineer`` and ``manager``, in our
784previous examples):
785
786.. sourcecode:: python+sql
787
788    {opensql}
789    SELECT employee.id AS employee_id,
790        employee.name AS employee_name, employee.type AS employee_type
791    FROM employee
792    []
793
794After a collection of ``Employee`` objects has been returned from the
795query, and as attributes are requested from those ``Employee`` objects which are
796represented in either the ``engineer`` or ``manager`` child tables, a second
797load is issued for the columns in that related row, if the data was not
798already loaded. So above, after accessing the objects you'd see further SQL
799issued along the lines of:
800
801.. sourcecode:: python+sql
802
803    {opensql}
804    SELECT manager.id AS manager_id,
805        manager.manager_data AS manager_manager_data
806    FROM manager
807    WHERE ? = manager.id
808    [5]
809    SELECT engineer.id AS engineer_id,
810        engineer.engineer_info AS engineer_engineer_info
811    FROM engineer
812    WHERE ? = engineer.id
813    [2]
814
815The :func:`_orm.with_polymorphic`
816function and related configuration options allow us to instead emit a JOIN up
817front which will conditionally load against ``employee``, ``engineer``, or
818``manager``, very much like joined eager loading works for relationships,
819removing the necessity for a second per-entity load::
820
821    from sqlalchemy.orm import with_polymorphic
822
823    eng_plus_manager = with_polymorphic(Employee, [Engineer, Manager])
824
825    query = session.query(eng_plus_manager)
826
827The above produces a query which joins the ``employee`` table to both the
828``engineer`` and ``manager`` tables like the following:
829
830.. sourcecode:: python+sql
831
832    query.all()
833    {opensql}
834    SELECT employee.id AS employee_id,
835        engineer.id AS engineer_id,
836        manager.id AS manager_id,
837        employee.name AS employee_name,
838        employee.type AS employee_type,
839        engineer.engineer_info AS engineer_engineer_info,
840        manager.manager_data AS manager_manager_data
841    FROM employee
842        LEFT OUTER JOIN engineer
843        ON employee.id = engineer.id
844        LEFT OUTER JOIN manager
845        ON employee.id = manager.id
846    []
847
848The section :ref:`with_polymorphic` discusses the :func:`_orm.with_polymorphic`
849function and its configurational variants.
850
851.. seealso::
852
853    :ref:`with_polymorphic`
854
855.. _loading_single_inheritance:
856
857Loading objects with single table inheritance
858---------------------------------------------
859
860In modern Declarative, single inheritance mappings produce :class:`_schema.Column`
861objects that are mapped only to a subclass, and not available from the
862superclass, even though they are present on the same table.
863In our example from :ref:`single_inheritance`, the ``Manager`` mapping for example had a
864:class:`_schema.Column` specified::
865
866    class Manager(Employee):
867        manager_data = Column(String(50))
868
869        __mapper_args__ = {
870            'polymorphic_identity':'manager'
871        }
872
873Above, there would be no ``Employee.manager_data``
874attribute, even though the ``employee`` table has a ``manager_data`` column.
875A query against ``Manager`` will include this column in the query, as well
876as an IN clause to limit rows only to ``Manager`` objects:
877
878.. sourcecode:: python+sql
879
880    session.query(Manager).all()
881    {opensql}
882    SELECT
883        employee.id AS employee_id,
884        employee.name AS employee_name,
885        employee.type AS employee_type,
886        employee.manager_data AS employee_manager_data
887    FROM employee
888    WHERE employee.type IN (?)
889
890    ('manager',)
891
892However, in a similar way to that of joined table inheritance, a query
893against ``Employee`` will only query for columns mapped to ``Employee``:
894
895.. sourcecode:: python+sql
896
897    session.query(Employee).all()
898    {opensql}
899    SELECT employee.id AS employee_id,
900        employee.name AS employee_name,
901        employee.type AS employee_type
902    FROM employee
903
904If we get back an instance of ``Manager`` from our result, accessing
905additional columns only mapped to ``Manager`` emits a lazy load
906for those columns, in a similar way to joined inheritance::
907
908    SELECT employee.manager_data AS employee_manager_data
909    FROM employee
910    WHERE employee.id = ? AND employee.type IN (?)
911
912The :func:`_orm.with_polymorphic` function serves a similar role as  joined
913inheritance in the case of single inheritance; it allows both for eager loading
914of subclass attributes as well as specification of subclasses in a query,
915just without the overhead of using OUTER JOIN::
916
917    employee_poly = with_polymorphic(Employee, '*')
918
919    q = session.query(employee_poly).filter(
920        or_(
921            employee_poly.name == 'a',
922            employee_poly.Manager.manager_data == 'b'
923        )
924    )
925
926Above, our query remains against a single table however we can refer to the
927columns present in ``Manager`` or ``Engineer`` using the "polymorphic" namespace.
928Since we specified ``"*"`` for the entities, both ``Engineer`` and
929``Manager`` will be loaded at once.  SQL emitted would be:
930
931.. sourcecode:: python+sql
932
933    q.all()
934    {opensql}
935    SELECT
936        employee.id AS employee_id, employee.name AS employee_name,
937        employee.type AS employee_type,
938        employee.manager_data AS employee_manager_data,
939        employee.engineer_info AS employee_engineer_info
940    FROM employee
941    WHERE employee.name = :name_1
942    OR employee.manager_data = :manager_data_1
943
944
945Inheritance Loading API
946-----------------------
947
948.. autofunction:: sqlalchemy.orm.with_polymorphic
949
950.. autofunction:: sqlalchemy.orm.selectin_polymorphic
951