我确实找到了答案,我想我会回来展示我是如何做到的。
经过一番搜索,我发现了this question,它成为了解决方案的基础。这并不准确,但它表明,如果你知道如何去做,这些 @declared_attr 东西可以是可变的。
所以让我们从 target_id 属性开始,这就是我在这里所拥有的。还有更多,我会讲到,但我会从那个开始。顺便说一句,这都在“父”混入中。
基本模式是您需要一个 setter、一个 getter 和一个变量本身,如下所示:
_targetTableName = 'Not defined target table name'
def get_targetTableName(self):
return self._targetTableName
def set_targetTableName(self, value):
self._targetTableName = value
@declared_attr
def targetTableName(cls):
return synonym('_targetTableName', descriptor=property(cls.get_targetTableName, cls.set_targetTableName))
那么我在同一个 mixin 中也需要这个:
@declared_attr
def target_id(cls):
return Column('target_id', ForeignKey(f'{cls.targetTableName}.ID'))
如您所见,这允许我更改 ForeignKey 参数中的内容 - 毕竟它只是一个字符串。
作为一个相对新手,我要问的下一个问题是如何更改孩子的这个“targetTableName”属性?好吧,就像这样:
class TestChild(TestParent, med.DeclarativeBase):
__tablename__='testChild01'
targetTableName = 'SchoolTypes'
现在,当它全部自动创建后,您的子类将有一个外键,在本例中为 SchoolTypes.ID。
但是等等,如果目标中的列不称为“ID”怎么办?好吧,您也可以以相同的方式将其设为变量。我选择不这样做是因为我所有的表都有一个“ID”列(我不知道这是好还是坏的做法)。
但是等等,还有更多!
你看,实际上 target_id 只是等式的一部分,我希望,如果我能解决这个问题,我就能得到奖品的另一部分:链接对象。也就是说,SQLAlchemy 的“关系”类型为您提供由外键链接的对象。
正常创建时是这样的:
targetType = relationship('SchoolType', foreign_keys='Search_Grade_SchoolType.targetID')
那么如何使这个通用呢?好吧,用与上面相同的过程来使设置的东西可变。
让我与您分享整个代码,使其更易于查看。但请注意,我所做的只是为目标表名、目标类名和当前类名设置了一个变量,所有这些都是您需要的:
from sqlalchemy import Column, Integer, Boolean, String, DateTime, ForeignKey
from sqlalchemy.orm import backref, relationship
from sqlalchemy.orm import declarative_mixin, synonym
from sqlalchemy.orm import declared_attr
@declarative_mixin
class TestParent:
id = Column('ID', Integer, primary_key=True, autoincrement=True)
_targetTableName = 'Not defined target table name'
_targetClassName = 'Not defined target class name'
_myClassName = 'Not defined class name'
def get_myClassName(self):
return self._myClassName
def set_myClassName(self, value):
self._myClassName = value
@declared_attr
def myClassName(cls):
return synonym('_myClassName', descriptor=property(cls.get_myClassName, cls.set_myClassName))
def get_targetTableName(self):
return self._targetTableName
def set_targetTableName(self, value):
self._targetTableName = value
@declared_attr
def targetTableName(cls):
return synonym('_targetTableName', descriptor=property(cls.get_targetTableName, cls.set_targetTableName))
def get_targetClassName(self):
return self._targetClassName
def set_targetClassName(self, value):
self._targetClassName = value
@declared_attr
def target_id(cls):
return Column('target_id', ForeignKey(f'{cls.targetTableName}.ID'))
@declared_attr
def targetClassName(cls):
return synonym('_targetClassName', descriptor=property(cls.get_targetClassName, cls.set_targetClassName))
@declared_attr
def target_object(cls):
return relationship(f'{cls.targetClassName}', foreign_keys=f'{cls.myClassName}.target_id')
class TestChild(TestParent, med.DeclarativeBase):
__tablename__='testChild01'
name = Column('NAME', String(50), unique=False)
targetTableName = 'SchoolTypes'
targetClassName = 'SchoolType'
myClassName = 'TestChild'
def __init__(self, name, targetID):
self.name = name
self.target_id = targetID
def TestMethod(self):
print(f'Print me!')
那么这一切有什么作用呢?它允许子类(TestChild)通过在子类中输入一些变量来设置target_object和target_id等。父级可以拥有任意数量的列,子级也可以拥有它们,但它们也可以拥有自己的列(在这种情况下,父级的“ID”,子级的“名称”。
我为什么要做这一切?它解决了什么问题?好吧,我知道我会有很多实际上是相同的表。相同的结构,除了它们彼此具有不同表的外键。所以我想要某种继承情况来允许代码重用,也让我变得懒惰。