Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sqlalchemy: avoiding multiple inheritance and having abstract base class

Tags:

So I have a bunch of tables using SQLAlchemy that are modelled as objects which inherit from the result to a call to declarative_base(). Ie:

Base = declarative_base() class Table1(Base):     # __tablename__ & such here  class Table2(Base):      # __tablename__ & such here 

Etc. I then wanted to have some common functionality available to each of my DB table classes, the easiest way to do this according to the docs is to just do multiple inheritance:

Base = declarative_base()  class CommonRoutines(object):     @classmethod     def somecommonaction(cls):         # body here  class Table1(CommonRoutines, Base):     # __tablename__ & such here  class Table2(CommonRoutines, Base):      # __tablename__ & such here 

The thing I don't like about this is A) multiple inheritance in general is a bit icky (gets tricky resolving things like super() calls, etc), B) if I add a new table I have to remember to inherit from both Base and CommonRoutines, and C) really that "CommonRoutines" class "is-a" type of table in a sense. Really what CommonBase is is an abstract base class which defines a set of fields & routines which are common to all tables. Put another way: "its-a" abstract table.

So, what I'd like is this:

Base = declarative_base()  class AbstractTable(Base):     __metaclass__ = ABCMeta  # make into abstract base class      # define common attributes for all tables here, like maybe:     id = Column(Integer, primary_key=True)      @classmethod     def somecommonaction(cls):         # body here  class Table1(AbstractTable):     # __tablename__ & Table1 specific fields here  class Table2(AbstractTable):      # __tablename__ & Table2 specific fields here 

But this of course doesn't work, as I then have to A) define a __tablename__ for AbstractTable, B) the ABC aspect of things causes all sorts of headaches, and C) have to indicate some sort of DB relationship between AbstractTable and each individual table.

So my question: is it possible to achieve this in a reasonable way? Ideally I'd like to enforce:

  • No multiple inheritance
  • CommonBase/AbstractTable be abstract (ie cannot be instantiated)
like image 650
Adam Parkin Avatar asked Mar 07 '12 17:03

Adam Parkin


1 Answers

SQLAlchemy version 0.7.3 introduced the __abstract__ directive which is used for abstract classes that should not be mapped to a database table, even though they are subclasses of sqlalchemy.ext.declarative.api.Base. So now you create a base class like this:

Base = declarative_base()  class CommonRoutines(Base):     __abstract__ = True      id = Column(Integer, primary_key=True)      def __init__(self):         # ... 

Notice how CommonRoutines doesn't have a __tablename__ attribute. Then create subclasses like this:

class Foo(CommonRoutines):     __tablename__ = 'foo'      name = Column(...)      def __init__(self, name):         super().__init__()         self.name = name         # ... 

This will map to the table foo and inherit the id attribute from CommonRoutines.

Source and more information: http://docs.sqlalchemy.org/en/rel_0_7/orm/extensions/declarative.html#abstract

like image 128
Anton Eliasson Avatar answered Oct 17 '22 21:10

Anton Eliasson