On Tue, Jun 10, 2014 at 8:47 PM, Noah Davis <neopygmal...@gmail.com> wrote: > Hi, > I've been banging my head against this one for several days now, and > aside from a three year-old post here, I've come up empty. > > I've got a python module that defines a set of Declarative models that > several other applications may use. What I'd like is some way to for the > individual applications to sub-class the existing Declarative objects, > without adding any new SQL functionality. Specifically, I'd just like to add > application-specific helper code to the objects. As an example. > > some_model.py > --------------------------------------- > [SQLA setup of Base class here] > class Alice(Base): > __tablename__ = 'alice' > id = Column(Integer, primary_key=True) > value = Column(String) > > class Bob(Base): > __tablename__ = 'bob' > id = Column(Integer, primary_key=True) > subval = Column(String) > alice_id = Colum(Integer, ForeignKey('alice.id')) > alice = relationship('Alice', backref='bobs') > ---------------------------------------- > > some_app.py > ---------------------------------------- > import some_model > > class MyAlice(some_model.Alice): > def myfunc(self): > do_nothing_sql_related_here() > > class MyBob(some_model.Bob): > def otherfunc(self): > again_something_unrelated() > ----------------------------------------- > > This actually works okay out of the box if I select on the subclasses: > DBSession.query(MyAlice).filter(MyAlice.id==5).first() -> MyAlice(...) > > The problem, of course, is relations: > a = DBSession.query(MyAlice).filter(MyAlice.id=1).first() > a.bobs -> [Bob(...), Bob(...), Bob(...)] > instead of > a.bobs -> [MyBob(...), MyBob(...), MyBob(...)] > > I suspect there's some way to tell the ORM to Do The Right Thing here, but I > have no idea what it might be. I'd like the particular applications to be as > unaware of the underlying table information as possible. I guess in essence > I'm trying to separate business logic from the DB logic as much as possible. > Maybe I'm heading down a dead-end... I'm open to better suggestions. > > Thanks, > Noah >
Is it really very important to you that "myfunc" and "otherfunc" are methods of your mapped objects, rather than functions defined somewhere else that take an Alice or Bob object as a parameter? I used to write code where pretty much everything that *could* be a method of a class *was* a method of that class, and my classes became unwieldy and difficult to test as a result. Recently I've been trying to keep my classes small and write more functions instead, and I think it has been a general improvement. Having said that, if you *really* want these functions to be available as methods of your classes, and you only want a single "application" within each process, you could monkeypatch the methods in: def myfunc(self): do_nothing_sql_related_here() some_model.Alice.myfunc = myfunc You could wrap the monkeypatching up in a decorator (untested): def monkeypatch(cls): def patcher(f): setattr(cls, f.__name__, f) return patcher @monkeypatch(some_model.Alice) def myfunc(self): do_nothing_sql_related_here() (This is pretty nasty really, but depending on your requirements it might be the easiest way to make it work) Hope that helps, Simon -- 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 http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.