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