从 SQLAlchemy 联接表继承类继承



Python 3.6 和 SQLAlchemy 1.2.

我有一个名为events的包,它将Match定义为一种Event,并使用连接的表继承将其与其他类型的Event区分开来。另一种类型的事件是Competition,所有事件都是一个或另一个:

class Event(Base):
__tablename__ = 'tbl_events'
event_id = Column(Integer, primary_key=True)
event_type_id = Column(String(50))  # 0 is Match, 1 is Competition
__mapper_args__ = {'polymorphic_on': event_type_id}
class Match(Event):
__tablename__ = 'tbl_match_details'
event_id = Column(Integer,
ForeignKey('tbl_events.event_id'),
primary_key=True)
team_1 = Column(String(50))
team_2 = Column(String(50))
__mapper_args__ = {'polymorphic_identity': 0}

我在另一个包中使用Match,该包区分多种类型的Match,并依靠Match对象的属性和方法从数据库中提取事件信息,但在远离数据库的情况下运行:

from events import Match
class BaseMatch(Match):
# define common methods and attrs
class TennisMatch(BaseMatch):
# do Tennis based stuff
class FootballMatch(BaseMatch):
# do football based things

events.Match和从它继承的类之间的任何差异都只在此包中很重要,并且此包不会以其他方式插入或更新数据库,仅从中读取。

我遇到的问题是,尝试实例化从Match继承的任何类的实例会导致将NULL值传递到event_type_id字段的查询中。这是查询的WHERE部分:

WHERE tbl_match_details.event_id = %s AND tbl_events.match_comp_id IN (NULL)

我不能简单地为每个类提供自己的多态标识符,因为这些标识符不会存在于数据库中。

我试过这个:

class BaseMatch(Match):
@declared_attr
def __mapper_args__(cls):
return {'polymorphic_identity': 0}
class TennisMatch(BaseMatch):
# do tennis stuff
class FootballMatch(BaseMatch):
# do footy stuff

但是导入模块,我收到如下警告:

SAWarning: Reassigning polymorphic association for identity 0 from <Mapper at 0x7f80197f0550; Match> to <Mapper at 0x7f80197a9fd0; BaseModel>: Check for duplicate use of 0 as value for polymorphic_identity.
SAWarning: Reassigning polymorphic association for identity 0 from <Mapper at 0x7f80197a9fd0; BaseModel> to <Mapper at 0x7f800dfdf940; TennisMatch>: Check for duplicate use of 0 as value for polymorphic_identity.

对于从Match继承的每个类,我都会得到一个,当我尝试实例化任何匹配类型时,我得到了与该多态 id 关联的最后一个类型的实例。

我真的很感激朝着正确的方向推动!

谢谢。

这是我为解决这个问题所做的工作 - 我不确定它是否"正确",但它让我能够继续我正在做的事情,并帮助我更多地了解引擎盖下发生的事情。

我在事件、竞赛和比赛类上创建了一个工厂方法,并在竞争和比赛上创建了一个类属性,使我能够访问每个事件类型的event_type_id值:

from sqlalchemy import inspect
class Event(Base):
__tablename__ = 'tbl_events'
event_id = Column(Integer, primary_key=True)
event_type_id = Column(String(50))  # 0 is Match, 1 is Competition
__mapper_args__ = {'polymorphic_on': event_type_id}
@classmethod
def from_id(cls, id, session):
mapper = inspect(cls).mapper
mapper.polymorphic_map[cls.EVENT_TYPE_ID] = mapper
mapper.polymorphic_identity = cls.EVENT_TYPE_ID
return session.query(cls).filter_by(event_id=id).one()
class Match(Event):
EVENT_TYPE_ID = 0
__tablename__ = 'tbl_match_details'
event_id = Column(Integer,
ForeignKey('tbl_events.event_id'),
primary_key=True)
team_1 = Column(String(50))
team_2 = Column(String(50))
__mapper_args__ = {'polymorphic_identity': EVENT_TYPE_ID}

这样,每当使用工厂方法实例化从 Match 或 Competition 继承的类时,多态标识都会强制为父类上定义的标识,并且多态映射将该标识指向调用工厂的类。

对我来说显而易见的一个缺点是,这仅在通过工厂方法实例化对象时才有效。在这种情况下很好,但可能不适合所有人。

希望得到有关我如何做到这一点的任何反馈以及任何指向更清洁解决方案的指示。

谢谢

最新更新