Hi, I am struggling since some days to extend and implement common class inheritance for the SQLAlchemy ORM objects that I define: Here is the to be achieved task: 1. In a first step, I want to use sqlalchemy to model my database and the ORM, aka define tables, define the ORMs and their relations and some extras (association mapper) in Order to make my live easier 2. In a second step I want to take the ORMs and extend the classes with some higher level functionality, modeling common operations which will be executed in the database. 3. In a third step, I'd like to take the extended ORMs from step 2 and extend them again with further convenience functions, which are, however, separate from the db-model logic.
To logically isolate and structure the whole thing, I want to wrap each of these steps into a dedicated module/package. This I would have solved by class Inheritance, which seams to be the natural approach. However, for all methods which I tried, I cannot figure out how this done correctly even in mock scripts. I will post below some example code which should demonstrate what I want to achieve. I tried multiple approaches: - with classical mapping (wont work, because i need to explicitly map every derived class again, copying all mapper attributes, I would have to double paste a lot of code, which is exactly not the point of inheritance) - with declarative (there is some deep magic to these @declarative_attributes, which I do not understand when to use and when not, respective at which point they are resolved) - with hybrid approach, my currently preferred one, as I have at least the table definitions done, before messing with the ORM I could for all of them not find a single solution which would fulfill all my needs or which do not throw errors: Errors include: - The derived class-names cannot be resolved for the relation to work correctly - The attributes (relation, association_proxy) do not propagate up to the derived classes (I have the feeling they bind to the first concrete mapped class they are in and inheritance onward is impossible) If anybody could give me some pointers or make the below code example work by some magic alchemistic conjurement I would be very grateful. Marcel ==================Example Code =================== import datetime as dt from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import MetaData, Table, Column, Sequence, ForeignKey from sqlalchemy import Integer, String, DateTime from sqlalchemy.orm import relationship from sqlalchemy.ext.associationproxy import association_proxy from sqlalchemy.orm import Session from sqlalchemy import create_engine from sqlalchemy.orm.session import object_session metadata = MetaData(schema='sandbox') source_table = Table('source', metadata, Column('id', Integer, Sequence("src_id_seq", metadata=metadata), primary_key=True), Column('name', String(length=32), unique=True, nullable=False, index=True), Column('created', DateTime(timezone=False), default=dt.datetime.utcnow, nullable=False), Column('loc_id', ForeignKey(user_table.c.id), nullable=True)) location_table = Table('auth_user_detail', metadata, Column('id', Integer, Sequence("loc_id_seq", metadata=metadata), primary_key=True), Column('name', String(length=32), unique=True, nullable=False, index=True), Column('created', DateTime(timezone=False), default=dt.datetime.utcnow, nullable=False)) ) # base definition of the Source-class for Mapper Base = declarative_base(metadata) class Source_orm(Base): __table__ = source_table _loc = relationship('Location', uselist=False) loc_name = association_proxy('_loc', 'firstname') def __init__(self, name): self.name = name # base definition of the Location-class for Mapping class Location_orm(Base): __table__ = location_table def __init__(self, name): self.name = name #------------------- # Higher functions - lvlA : possibly packed into a different module class Source_lvlA(Source_orm): @classmethod def get_by_name(cls, session, name): return session.query(cls).filter(cls.name == name).one() def move_to_loc_by_name(self, loc_name): session = object_session(self) loc = session.query(Location).filter(Location.name == loc_name).one() self._loc = loc session.commit() class Location_lvlA(Location_orm): @classmethod def get_by_name(cls, session, name): return session.query(cls).filter(cls.name == name).one() def move_src_here(self, src): session = object_session(self) src.loc_id = self.id session.merge(src) session.commit() #------------------- # Even Higher functions - lvlB : possibly packed into a different module class Source_lvlB(Source_lvlA): def assemble_info(self): return f"<Source> {self.name} at <Location> {self.loc_name}" class Location_lvlB(Location_lvlA): def assemble_info(self): return f"<Location> {self.name}" if __name__ == '__main__': engine = create_engine("sqlite://", echo=True) engine.execute("""DROP SCHEMA IF EXISTS {schema} CASCADE; """.format(schema=metadata.schema)) engine.execute("""CREATE SCHEMA {schema};""".format(schema=metadata.schema)) Base.metadata.create_all(engine) session = Session(engine) # create low level objects s = Source_ormA('MySource') s = session.add(a) session.flush() l = Location_lvlA('MyLocation') l = session.add(l) session.flush() # operate on the db use a higher level function s = Source_lvlA.get_by_name(session, 'MySource') s.move_to_loc(Location_lvlB.get_by_name('MyLocation')) # use highest level functionality s = Source_lvlB.get_by_name(session, 'MySource').assemble_info() -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. To view this discussion on the web visit https://groups.google.com/d/msgid/sqlalchemy/ed3a4914-2b37-4f2e-b213-3c615b85c367%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.