SQLAlchemy的類繼承、抽象類

Python中的類繼承是相當容易的,但是在SQLAlchemy中卻不能直接用Python類繼承完成,還要多加一些設置。

網上關於這個東西,東說西說的非常多,甚至官網都沒有把最簡單的解決方案po出來,取而代之的是非常複雜的Inheritance Configuration

首先說最簡單的方案,來自Stackoverflow,親測完美有效,最符合Python類繼承。

參考:Sqlalchemy: avoiding multiple inheritance and having abstract base class

正解

在這裏,我們稱這個方法爲__abstract__方法:

Base = declarative_base()

class CommonRoutines(Base):
    __abstract__ = True

    id = Column(Integer, primary_key=True)

    def __init__(self):
        # ...

class Foo(CommonRoutines):
    __tablename__ = 'foo'

    name = Column(...)

    def __init__(self, name):
        super().__init__()
        self.name = name
        # ...

也就是說,抽象類中只要用__abstract__ = True代替__tablename__即可完成一切工作,其它一切都和Python內置的類繼承一摸一樣了。

繼承中的類方法和靜態方法

SQLAlchemy的ORM繼承,在classmethodstaticmethod繼承是和Python OOP面向對象的繼承方案一致的。

也就是說:

  • 被冠之@staticmethod的靜態方法,會被繼承,但是在子類調用的時候,卻是調用的父類同名方法。
  • 被冠之@classmethod的類方法,會被繼承,子類調用的時候就是調用子類的這個方法。

繼承中的外鍵

奇怪的是,SQLAlchemy定義的ORM,在繼承父級ORM時候,Foreign Key外鍵是不能繼承的,它強制要求在子類中重新定義。
參考官方文檔:Mapping Class Inheritance Hierarchies 建議直接用Ctrl-f搜索"foreign`關鍵字,就能看到官方在繼承時,也都要重新定義一遍外鍵。

再參考:SQLAlchemy Inheritance

class Parent(Base):
    __abstract__ = True

    id = Column('id', Integer, primary_key=True)
    name = Column('name', String)
    age = Column('age', String)
    fk = Column('fk', Integer, ForeignKey('anotherTable.id'), primary_key=True)

class Son(Parent):
    __tablename__ = 'son'

    fk = Column('fk', Integer, ForeignKey('anotherTable.id'), primary_key=True)

其它繼承方案

如果參考別人的方案、官網的方案,會讓你暈頭轉向。
爲了避免重複參考別人的東西,這裏貼上一些不是解決方案的解決方案

declarative_base(cls=XX)方法:

class CommonBase(object):
    @classmethod
    def somecommonaction(cls):
        # body here

Base = declarative_base(cls=CommonBase)

class Table1(Base):
    # __tablename__ & Table1 specific fields here

class Table2(Base):
     # __tablename__ & Table2 specific fields here

這樣的缺點是,很難看清繼承關係。

官方的__mapper_args__方法:

class Person(Base):
    __tablename__ = 'people'
    id = Column(Integer, primary_key=True)
    discriminator = Column('type', String(50))
    __mapper_args__ = {'polymorphic_on': discriminator}

class Engineer(Person):
    __tablename__ = 'engineers'
    __mapper_args__ = {'polymorphic_identity': 'engineer'}
    id = Column(Integer, ForeignKey('people.id'), primary_key=True)
    primary_language = Column(String(50))

可以看出,這個必須在父子類都中分別定義難懂的__mapper_args__屬性。這還不算完,官網中還說各種映射需要不同的複雜設置。有興趣可參考官網:https://docs.sqlalchemy.org/e...

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章