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繼承,在classmethod
和staticmethod
繼承是和Python OOP面向對象的繼承方案一致的。
也就是說:
- 被冠之
@staticmethod
的靜態方法,會被繼承,但是在子類調用的時候,卻是調用的父類同名方法。 - 被冠之
@classmethod
的類方法,會被繼承,子類調用的時候就是調用子類的這個方法。
繼承中的外鍵
奇怪的是,SQLAlchemy定義的ORM,在繼承父級ORM時候,Foreign Key
外鍵是不能繼承的,它強制要求在子類中重新定義。
參考官方文檔:Mapping Class Inheritance Hierarchies 建議直接用Ctrl-f
搜索"foreign`關鍵字,就能看到官方在繼承時,也都要重新定義一遍外鍵。
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...