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
对象的attribs和方法从数据库中提取事件信息,但是远离数据库运行,否则就是:
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,Competition和Match类上创建了一个工厂方法,在Competition和Match上创建了一个class属性,可以访问每个事件类型的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继承的类时,多态标识将被强制转换为父类上定义的标识,并且多态映射将该标识指向要调用工厂的类。
对我来说显而易见的一个缺点是,只有在通过工厂方法实例化对象时,这才会起作用。在这种情况下很好,但可能不是全部。
非常感谢任何关于我如何解决这个问题的反馈以及任何针对更清洁解决方案的指示。
谢谢