diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2017-05-16 09:51:06 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2017-05-16 09:51:06 -0400 |
commit | 5329fc481ed1dcea0e922fd63def3094bda12c91 (patch) | |
tree | 827aaac0ff4b7c9897aa3468d8593fe3fed54c84 /examples/inheritance/single.py | |
parent | b5697334789a84e4dec2729053ab6a6640855ac8 (diff) | |
download | sqlalchemy-5329fc481ed1dcea0e922fd63def3094bda12c91.tar.gz |
modernize and repair inheritance examples
remarkably, the examples for concrete and single were still
using classical mappings. Ensure all three examples use
modern declarative patterns, each illustrate the identical set
of query operations. Use back_populates, flat=True for joins,
etc. ensure flake8 linting, correct links and add a link back
from newly reworked inheritance documentation.
Change-Id: I8465a9badbb0eda804f457ccac599f051ee3c27c
Diffstat (limited to 'examples/inheritance/single.py')
-rw-r--r-- | examples/inheritance/single.py | 199 |
1 files changed, 127 insertions, 72 deletions
diff --git a/examples/inheritance/single.py b/examples/inheritance/single.py index 22a6fe027..56397f540 100644 --- a/examples/inheritance/single.py +++ b/examples/inheritance/single.py @@ -1,102 +1,157 @@ -"""Single-table inheritance example.""" - -from sqlalchemy import MetaData, Table, Column, Integer, String, \ - ForeignKey, create_engine -from sqlalchemy.orm import mapper, relationship, sessionmaker - -metadata = MetaData() - -# a table to store companies -companies = Table('companies', metadata, - Column('company_id', Integer, primary_key=True), - Column('name', String(50))) - -employees_table = Table('employees', metadata, - Column('employee_id', Integer, primary_key=True), - Column('company_id', Integer, ForeignKey('companies.company_id')), - Column('name', String(50)), - Column('type', String(20)), - Column('status', String(20)), - Column('engineer_name', String(50)), - Column('primary_language', String(50)), - Column('manager_name', String(50)) -) +"""Single-table (table-per-hierarchy) inheritance example.""" + +from sqlalchemy import Column, Integer, String, \ + ForeignKey, create_engine, inspect, or_ +from sqlalchemy.orm import relationship, Session, with_polymorphic +from sqlalchemy.ext.declarative import declarative_base, declared_attr + +Base = declarative_base() + +class Company(Base): + __tablename__ = 'company' + id = Column(Integer, primary_key=True) + name = Column(String(50)) + + employees = relationship( + "Person", + back_populates='company', + cascade='all, delete-orphan') + + def __repr__(self): + return "Company %s" % self.name + + +class Person(Base): + __tablename__ = 'person' + id = Column(Integer, primary_key=True) + company_id = Column(ForeignKey('company.id')) + name = Column(String(50)) + type = Column(String(50)) + + company = relationship("Company", back_populates="employees") + + __mapper_args__ = { + 'polymorphic_identity': 'person', + 'polymorphic_on': type + } -class Person(object): - def __init__(self, **kwargs): - for key, value in kwargs.items(): - setattr(self, key, value) def __repr__(self): return "Ordinary person %s" % self.name + + class Engineer(Person): - def __repr__(self): - return "Engineer %s, status %s, engineer_name %s, "\ - "primary_language %s" % \ - (self.name, self.status, - self.engineer_name, self.primary_language) -class Manager(Person): - def __repr__(self): - return "Manager %s, status %s, manager_name %s" % \ - (self.name, self.status, self.manager_name) -class Company(object): - def __init__(self, **kwargs): - for key, value in kwargs.items(): - setattr(self, key, value) - def __repr__(self): - return "Company %s" % self.name -person_mapper = mapper(Person, employees_table, - polymorphic_on=employees_table.c.type, - polymorphic_identity='person') -manager_mapper = mapper(Manager, inherits=person_mapper, - polymorphic_identity='manager') -engineer_mapper = mapper(Engineer, inherits=person_mapper, - polymorphic_identity='engineer') + engineer_name = Column(String(30)) + primary_language = Column(String(30)) -mapper(Company, companies, properties={ - 'employees': relationship(Person, lazy=True, backref='company') -}) + # illustrate a single-inh "conflicting" column declaration; + # see http://docs.sqlalchemy.org/en/latest/orm/extensions/ + # declarative/inheritance.html#resolving-column-conflicts + @declared_attr + def status(cls): + return Person.__table__.c.get('status', Column(String(30))) + __mapper_args__ = { + 'polymorphic_identity': 'engineer', + } -engine = create_engine('sqlite:///', echo=True) + def __repr__(self): + return ( + "Engineer %s, status %s, engineer_name %s, " + "primary_language %s" % + ( + self.name, self.status, + self.engineer_name, self.primary_language) + ) + + +class Manager(Person): + manager_name = Column(String(30)) -metadata.create_all(engine) + @declared_attr + def status(cls): + return Person.__table__.c.get('status', Column(String(30))) -session = sessionmaker(engine)() + __mapper_args__ = { + 'polymorphic_identity': 'manager', + } -c = Company(name='company1') -c.employees.append(Manager(name='pointy haired boss', status='AAB', - manager_name='manager1')) -c.employees.append(Engineer(name='dilbert', status='BBA', - engineer_name='engineer1', primary_language='java')) -c.employees.append(Person(name='joesmith', status='HHH')) -c.employees.append(Engineer(name='wally', status='CGG', - engineer_name='engineer2', primary_language='python' - )) -c.employees.append(Manager(name='jsmith', status='ABA', - manager_name='manager2')) + def __repr__(self): + return "Manager %s, status %s, manager_name %s" % ( + self.name, self.status, self.manager_name) + + +engine = create_engine('sqlite://', echo=True) +Base.metadata.create_all(engine) + +session = Session(engine) + +c = Company(name='company1', employees=[ + Manager( + name='pointy haired boss', + status='AAB', + manager_name='manager1'), + Engineer( + name='dilbert', + status='BBA', + engineer_name='engineer1', + primary_language='java'), + Person(name='joesmith'), + Engineer( + name='wally', + status='CGG', + engineer_name='engineer2', + primary_language='python'), + Manager( + name='jsmith', + status='ABA', + manager_name='manager2') +]) session.add(c) + session.commit() c = session.query(Company).get(1) for e in c.employees: - print(e, e.company) - + print(e, inspect(e).key, e.company) +assert set([e.name for e in c.employees]) == set( + ['pointy haired boss', 'dilbert', 'joesmith', 'wally', 'jsmith']) print("\n") dilbert = session.query(Person).filter_by(name='dilbert').one() dilbert2 = session.query(Engineer).filter_by(name='dilbert').one() assert dilbert is dilbert2 -dilbert.engineer_name = 'hes dibert!' +dilbert.engineer_name = 'hes dilbert!' -session.flush() -session.expunge_all() +session.commit() c = session.query(Company).get(1) for e in c.employees: print(e) -session.delete(c) +# query using with_polymorphic. +eng_manager = with_polymorphic(Person, [Engineer, Manager]) +print( + session.query(eng_manager). + filter( + or_( + eng_manager.Engineer.engineer_name == 'engineer1', + eng_manager.Manager.manager_name == 'manager2' + ) + ).all() +) + +# illustrate join from Company, +eng_manager = with_polymorphic(Person, [Engineer, Manager]) +print( + session.query(Company). + join( + Company.employees.of_type(eng_manager) + ).filter( + or_(eng_manager.Engineer.engineer_name == 'engineer1', + eng_manager.Manager.manager_name == 'manager2') + ).all()) + session.commit() |