From fd8f60fcfe9cda0c2ba6dc9ddd171bf85a180295 Mon Sep 17 00:00:00 2001 From: Doctor Date: Thu, 28 Apr 2022 08:50:15 +0300 Subject: [PATCH] format `inheritance.rst` --- doc/build/orm/inheritance.rst | 366 ++++++++++++++++++++-------------- 1 file changed, 215 insertions(+), 151 deletions(-) diff --git a/doc/build/orm/inheritance.rst b/doc/build/orm/inheritance.rst index 4d4455b670..18bf98c4ed 100644 --- a/doc/build/orm/inheritance.rst +++ b/doc/build/orm/inheritance.rst @@ -45,14 +45,14 @@ additional arguments that will refer to the polymorphic discriminator column as well as the identifier for the base class:: class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity':'employee', - 'polymorphic_on':type + "polymorphic_identity": "employee", + "polymorphic_on": type, } Above, an additional column ``type`` is established to act as the @@ -82,21 +82,22 @@ they represent. Each table also must contain a primary key column (or columns), as well as a foreign key reference to the parent table:: class Engineer(Employee): - __tablename__ = 'engineer' - id = Column(Integer, ForeignKey('employee.id'), primary_key=True) + __tablename__ = "engineer" + id = Column(Integer, ForeignKey("employee.id"), primary_key=True) engineer_name = Column(String(30)) __mapper_args__ = { - 'polymorphic_identity':'engineer', + "polymorphic_identity": "engineer", } + class Manager(Employee): - __tablename__ = 'manager' - id = Column(Integer, ForeignKey('employee.id'), primary_key=True) + __tablename__ = "manager" + id = Column(Integer, ForeignKey("employee.id"), primary_key=True) manager_name = Column(String(30)) __mapper_args__ = { - 'polymorphic_identity':'manager', + "polymorphic_identity": "manager", } In the above example, each mapping specifies the @@ -159,29 +160,32 @@ the ``company`` table, the relationships are set up between ``Company`` and ``Employee``:: class Company(Base): - __tablename__ = 'company' + __tablename__ = "company" id = Column(Integer, primary_key=True) name = Column(String(50)) employees = relationship("Employee", back_populates="company") + class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(50)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) company = relationship("Company", back_populates="employees") __mapper_args__ = { - 'polymorphic_identity':'employee', - 'polymorphic_on':type + "polymorphic_identity": "employee", + "polymorphic_on": type, } + class Manager(Employee): - # ... + ... + class Engineer(Employee): - # ... + ... If the foreign key constraint is on a table corresponding to a subclass, the relationship should target that subclass instead. In the example @@ -190,36 +194,39 @@ key constraint from ``manager`` to ``company``, so the relationships are established between the ``Manager`` and ``Company`` classes:: class Company(Base): - __tablename__ = 'company' + __tablename__ = "company" id = Column(Integer, primary_key=True) name = Column(String(50)) managers = relationship("Manager", back_populates="company") + class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity':'employee', - 'polymorphic_on':type + "polymorphic_identity": "employee", + "polymorphic_on": type, } + class Manager(Employee): - __tablename__ = 'manager' - id = Column(Integer, ForeignKey('employee.id'), primary_key=True) + __tablename__ = "manager" + id = Column(Integer, ForeignKey("employee.id"), primary_key=True) manager_name = Column(String(30)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) company = relationship("Company", back_populates="managers") __mapper_args__ = { - 'polymorphic_identity':'manager', + "polymorphic_identity": "manager", } + class Engineer(Employee): - # ... + ... Above, the ``Manager`` class will have a ``Manager.company`` attribute; ``Company`` will have a ``Company.managers`` attribute that always @@ -263,28 +270,30 @@ subclasses, indicating that the column is to be mapped only to that subclass; the :class:`_schema.Column` will be applied to the same base :class:`_schema.Table` object:: class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(20)) __mapper_args__ = { - 'polymorphic_on':type, - 'polymorphic_identity':'employee' + "polymorphic_on": type, + "polymorphic_identity": "employee", } + class Manager(Employee): manager_data = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity':'manager' + "polymorphic_identity": "manager", } + class Engineer(Employee): engineer_info = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity':'engineer' + "polymorphic_identity": "engineer", } Note that the mappers for the derived classes Manager and Engineer omit the @@ -302,22 +311,28 @@ declaration on a subclass that has no table of its own. A tricky case comes up when two subclasses want to specify *the same* column, as below:: class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(20)) __mapper_args__ = { - 'polymorphic_on':type, - 'polymorphic_identity':'employee' + "polymorphic_on": type, + "polymorphic_identity": "employee", } + class Engineer(Employee): - __mapper_args__ = {'polymorphic_identity': 'engineer'} + __mapper_args__ = { + "polymorphic_identity": "engineer", + } start_date = Column(DateTime) + class Manager(Employee): - __mapper_args__ = {'polymorphic_identity': 'manager'} + __mapper_args__ = { + "polymorphic_identity": "manager", + } start_date = Column(DateTime) Above, the ``start_date`` column declared on both ``Engineer`` and ``Manager`` @@ -335,32 +350,39 @@ if it already exists:: from sqlalchemy.orm import declared_attr + class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(20)) __mapper_args__ = { - 'polymorphic_on':type, - 'polymorphic_identity':'employee' + "polymorphic_on": type, + "polymorphic_identity": "employee", } + class Engineer(Employee): - __mapper_args__ = {'polymorphic_identity': 'engineer'} + __mapper_args__ = { + "polymorphic_identity": "engineer", + } @declared_attr def start_date(cls): "Start date column, if not present already." - return Employee.__table__.c.get('start_date', Column(DateTime)) + return Employee.__table__.c.get("start_date", Column(DateTime)) + class Manager(Employee): - __mapper_args__ = {'polymorphic_identity': 'manager'} + __mapper_args__ = { + "polymorphic_identity": "manager", + } @declared_attr def start_date(cls): "Start date column, if not present already." - return Employee.__table__.c.get('start_date', Column(DateTime)) + return Employee.__table__.c.get("start_date", Column(DateTime)) Above, when ``Manager`` is mapped, the ``start_date`` column is already present on the ``Employee`` class; by returning the existing @@ -372,26 +394,33 @@ to define a particular series of columns and/or other mapped attributes from a reusable mixin class:: class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(20)) __mapper_args__ = { - 'polymorphic_on':type, - 'polymorphic_identity':'employee' + "polymorphic_on": type, + "polymorphic_identity": "employee", } + class HasStartDate: @declared_attr def start_date(cls): - return cls.__table__.c.get('start_date', Column(DateTime)) + return cls.__table__.c.get("start_date", Column(DateTime)) + class Engineer(HasStartDate, Employee): - __mapper_args__ = {'polymorphic_identity': 'engineer'} + __mapper_args__ = { + "polymorphic_identity": "engineer", + } + class Manager(HasStartDate, Employee): - __mapper_args__ = {'polymorphic_identity': 'manager'} + __mapper_args__ = { + "polymorphic_identity": "manager", + } Relationships with Single Table Inheritance +++++++++++++++++++++++++++++++++++++++++++ @@ -402,22 +431,23 @@ attribute should be on the same class that's the "foreign" side of the relationship:: class Company(Base): - __tablename__ = 'company' + __tablename__ = "company" id = Column(Integer, primary_key=True) name = Column(String(50)) employees = relationship("Employee", back_populates="company") + class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(50)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) company = relationship("Company", back_populates="employees") __mapper_args__ = { - 'polymorphic_identity':'employee', - 'polymorphic_on':type + "polymorphic_identity": "employee", + "polymorphic_on": type, } @@ -425,14 +455,15 @@ relationship:: manager_data = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity':'manager' + "polymorphic_identity": "manager", } + class Engineer(Employee): engineer_info = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity':'engineer' + "polymorphic_identity": "engineer", } Also, like the case of joined inheritance, we can create relationships @@ -441,31 +472,32 @@ include a WHERE clause that limits the class selection to that subclass or subclasses:: class Company(Base): - __tablename__ = 'company' + __tablename__ = "company" id = Column(Integer, primary_key=True) name = Column(String(50)) managers = relationship("Manager", back_populates="company") + class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) type = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity':'employee', - 'polymorphic_on':type + "polymorphic_identity": "employee", + "polymorphic_on": type, } class Manager(Employee): manager_name = Column(String(30)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) company = relationship("Company", back_populates="managers") __mapper_args__ = { - 'polymorphic_identity':'manager', + "polymorphic_identity": "manager", } @@ -473,7 +505,7 @@ or subclasses:: engineer_info = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity':'engineer' + "polymorphic_identity": "engineer", } Above, the ``Manager`` class will have a ``Manager.company`` attribute; @@ -533,31 +565,33 @@ This indicates to Declarative as well as the mapping that the superclass table should not be considered as part of the mapping:: class Employee(Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) + class Manager(Employee): - __tablename__ = 'manager' + __tablename__ = "manager" id = Column(Integer, primary_key=True) name = Column(String(50)) manager_data = Column(String(50)) __mapper_args__ = { - 'concrete': True + "concrete": True, } + class Engineer(Employee): - __tablename__ = 'engineer' + __tablename__ = "engineer" id = Column(Integer, primary_key=True) name = Column(String(50)) engineer_info = Column(String(50)) __mapper_args__ = { - 'concrete': True + "concrete": True, } Two critical points should be noted: @@ -604,36 +638,39 @@ almost the same way as we do other forms of inheritance mappings:: from sqlalchemy.ext.declarative import ConcreteBase + class Employee(ConcreteBase, Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) __mapper_args__ = { - 'polymorphic_identity': 'employee', - 'concrete': True + "polymorphic_identity": "employee", + "concrete": True, } + class Manager(Employee): - __tablename__ = 'manager' + __tablename__ = "manager" id = Column(Integer, primary_key=True) name = Column(String(50)) manager_data = Column(String(40)) __mapper_args__ = { - 'polymorphic_identity': 'manager', - 'concrete': True + "polymorphic_identity": "manager", + "concrete": True, } + class Engineer(Employee): - __tablename__ = 'engineer' + __tablename__ = "engineer" id = Column(Integer, primary_key=True) name = Column(String(50)) engineer_info = Column(String(40)) __mapper_args__ = { - 'polymorphic_identity': 'engineer', - 'concrete': True + "polymorphic_identity": "engineer", + "concrete": True, } Above, Declarative sets up the polymorphic selectable for the @@ -703,24 +740,26 @@ base class with the ``__abstract__`` indicator:: class Employee(Base): __abstract__ = True + class Manager(Employee): - __tablename__ = 'manager' + __tablename__ = "manager" id = Column(Integer, primary_key=True) name = Column(String(50)) manager_data = Column(String(40)) __mapper_args__ = { - 'polymorphic_identity': 'manager', + "polymorphic_identity": "manager", } + class Engineer(Employee): - __tablename__ = 'engineer' + __tablename__ = "engineer" id = Column(Integer, primary_key=True) name = Column(String(50)) engineer_info = Column(String(40)) __mapper_args__ = { - 'polymorphic_identity': 'engineer', + "polymorphic_identity": "engineer", } Above, we are not actually making use of SQLAlchemy's inheritance mapping @@ -751,29 +790,32 @@ class called :class:`.AbstractConcreteBase` which achieves this automatically:: from sqlalchemy.ext.declarative import AbstractConcreteBase + class Employee(AbstractConcreteBase, Base): pass + class Manager(Employee): - __tablename__ = 'manager' + __tablename__ = "manager" id = Column(Integer, primary_key=True) name = Column(String(50)) manager_data = Column(String(40)) __mapper_args__ = { - 'polymorphic_identity': 'manager', - 'concrete': True + "polymorphic_identity": "manager", + "concrete": True, } + class Engineer(Employee): - __tablename__ = 'engineer' + __tablename__ = "engineer" id = Column(Integer, primary_key=True) name = Column(String(50)) engineer_info = Column(String(40)) __mapper_args__ = { - 'polymorphic_identity': 'engineer', - 'concrete': True + "polymorphic_identity": "engineer", + "concrete": True, } The :class:`.AbstractConcreteBase` helper class has a more complex internal @@ -801,34 +843,41 @@ establishes the :class:`_schema.Table` objects separately:: metadata_obj = Base.metadata employees_table = Table( - 'employee', metadata_obj, - Column('id', Integer, primary_key=True), - Column('name', String(50)), + "employee", + metadata_obj, + Column("id", Integer, primary_key=True), + Column("name", String(50)), ) managers_table = Table( - 'manager', metadata_obj, - Column('id', Integer, primary_key=True), - Column('name', String(50)), - Column('manager_data', String(50)), + "manager", + metadata_obj, + Column("id", Integer, primary_key=True), + Column("name", String(50)), + Column("manager_data", String(50)), ) engineers_table = Table( - 'engineer', metadata_obj, - Column('id', Integer, primary_key=True), - Column('name', String(50)), - Column('engineer_info', String(50)), + "engineer", + metadata_obj, + Column("id", Integer, primary_key=True), + Column("name", String(50)), + Column("engineer_info", String(50)), ) Next, the UNION is produced using :func:`.polymorphic_union`:: from sqlalchemy.orm import polymorphic_union - pjoin = polymorphic_union({ - 'employee': employees_table, - 'manager': managers_table, - 'engineer': engineers_table - }, 'type', 'pjoin') + pjoin = polymorphic_union( + { + "employee": employees_table, + "manager": managers_table, + "engineer": engineers_table, + }, + "type", + "pjoin", + ) With the above :class:`_schema.Table` objects, the mappings can be produced using "semi-classical" style, where we use Declarative in conjunction with the ``__table__`` argument; @@ -838,22 +887,26 @@ the :paramref:`.mapper.with_polymorphic` parameter:: class Employee(Base): __table__ = employee_table __mapper_args__ = { - 'polymorphic_on': pjoin.c.type, - 'with_polymorphic': ('*', pjoin), - 'polymorphic_identity': 'employee' + "polymorphic_on": pjoin.c.type, + "with_polymorphic": ("*", pjoin), + "polymorphic_identity": "employee", } + class Engineer(Employee): __table__ = engineer_table __mapper_args__ = { - 'polymorphic_identity': 'engineer', - 'concrete': True} + "polymorphic_identity": "engineer", + "concrete": True, + } + class Manager(Employee): __table__ = manager_table __mapper_args__ = { - 'polymorphic_identity': 'manager', - 'concrete': True} + "polymorphic_identity": "manager", + "concrete": True, + } Alternatively, the same :class:`_schema.Table` objects can be used in fully "classical" style, without using Declarative at all. @@ -864,16 +917,19 @@ A constructor similar to that supplied by Declarative is illustrated:: for k in kw: setattr(self, k, kw[k]) + class Manager(Employee): pass + class Engineer(Employee): pass + employee_mapper = mapper_registry.map_imperatively( Employee, pjoin, - with_polymorphic=('*', pjoin), + with_polymorphic=("*", pjoin), polymorphic_on=pjoin.c.type, ) manager_mapper = mapper_registry.map_imperatively( @@ -881,18 +937,16 @@ A constructor similar to that supplied by Declarative is illustrated:: managers_table, inherits=employee_mapper, concrete=True, - polymorphic_identity='manager', + polymorphic_identity="manager", ) engineer_mapper = mapper_registry.map_imperatively( Engineer, engineers_table, inherits=employee_mapper, concrete=True, - polymorphic_identity='engineer', + polymorphic_identity="engineer", ) - - The "abstract" example can also be mapped using "semi-classical" or "classical" style. The difference is that instead of applying the "polymorphic union" to the :paramref:`.mapper.with_polymorphic` parameter, we apply it directly @@ -901,30 +955,40 @@ mapping is illustrated below:: from sqlalchemy.orm import polymorphic_union - pjoin = polymorphic_union({ - 'manager': managers_table, - 'engineer': engineers_table - }, 'type', 'pjoin') + pjoin = polymorphic_union( + { + "manager": managers_table, + "engineer": engineers_table, + }, + "type", + "pjoin", + ) + class Employee(Base): __table__ = pjoin __mapper_args__ = { - 'polymorphic_on': pjoin.c.type, - 'with_polymorphic': '*', - 'polymorphic_identity': 'employee' + "polymorphic_on": pjoin.c.type, + "with_polymorphic": "*", + "polymorphic_identity": "employee", } + class Engineer(Employee): __table__ = engineer_table __mapper_args__ = { - 'polymorphic_identity': 'engineer', - 'concrete': True} + "polymorphic_identity": "engineer", + "concrete": True, + } + class Manager(Employee): __table__ = manager_table __mapper_args__ = { - 'polymorphic_identity': 'manager', - 'concrete': True} + "polymorphic_identity": "manager", + "concrete": True, + } + Above, we use :func:`.polymorphic_union` in the same manner as before, except that we omit the ``employee`` table. @@ -955,47 +1019,47 @@ such a configuration is as follows:: class Company(Base): - __tablename__ = 'company' + __tablename__ = "company" id = Column(Integer, primary_key=True) name = Column(String(50)) employees = relationship("Employee") class Employee(ConcreteBase, Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) __mapper_args__ = { - 'polymorphic_identity': 'employee', - 'concrete': True + "polymorphic_identity": "employee", + "concrete": True, } class Manager(Employee): - __tablename__ = 'manager' + __tablename__ = "manager" id = Column(Integer, primary_key=True) name = Column(String(50)) manager_data = Column(String(40)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) __mapper_args__ = { - 'polymorphic_identity': 'manager', - 'concrete': True + "polymorphic_identity": "manager", + "concrete": True, } class Engineer(Employee): - __tablename__ = 'engineer' + __tablename__ = "engineer" id = Column(Integer, primary_key=True) name = Column(String(50)) engineer_info = Column(String(40)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) __mapper_args__ = { - 'polymorphic_identity': 'engineer', - 'concrete': True + "polymorphic_identity": "engineer", + "concrete": True, } The next complexity with concrete inheritance and relationships involves @@ -1015,50 +1079,50 @@ each of the relationships:: class Company(Base): - __tablename__ = 'company' + __tablename__ = "company" id = Column(Integer, primary_key=True) name = Column(String(50)) employees = relationship("Employee", back_populates="company") class Employee(ConcreteBase, Base): - __tablename__ = 'employee' + __tablename__ = "employee" id = Column(Integer, primary_key=True) name = Column(String(50)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) company = relationship("Company", back_populates="employees") __mapper_args__ = { - 'polymorphic_identity': 'employee', - 'concrete': True + "polymorphic_identity": "employee", + "concrete": True, } class Manager(Employee): - __tablename__ = 'manager' + __tablename__ = "manager" id = Column(Integer, primary_key=True) name = Column(String(50)) manager_data = Column(String(40)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) company = relationship("Company", back_populates="employees") __mapper_args__ = { - 'polymorphic_identity': 'manager', - 'concrete': True + "polymorphic_identity": "manager", + "concrete": True, } class Engineer(Employee): - __tablename__ = 'engineer' + __tablename__ = "engineer" id = Column(Integer, primary_key=True) name = Column(String(50)) engineer_info = Column(String(40)) - company_id = Column(ForeignKey('company.id')) + company_id = Column(ForeignKey("company.id")) company = relationship("Company", back_populates="employees") __mapper_args__ = { - 'polymorphic_identity': 'engineer', - 'concrete': True + "polymorphic_identity": "engineer", + "concrete": True, } The above limitation is related to the current implementation, including -- 2.47.3