我努力写这个问题。它进入了一个复杂而不常见的用例。
我在一个项目中定义了几个ORM类,负责维护公共数据库模式和核心功能。例如,让我们说这是model.email
模块。
from sqlalchemy import Column, Index, ForeignKey
from sqlalchemy import Boolean, Integer, Text
from . import Base
class CampaignDB(Base):
"""
Note: this basic database mapper class is expected to be extended.
When sub-classing, be mindful to override mappings to other extended classes.
"""
__tablename__ = 'campaigns'
audience_id = Column(Integer, ForeignKey("audiences.id"))
active = Column(Boolean)
name = Column(Text)
这些ORM类作为包导入到其他几个项目中。在某些情况下,这些ORM类被子类化以提供附加功能。例如,此处CampaignDB
类是子类,以便为在特定项目上下文中发送电子邮件提供支持。
from model.email import CampaignDB
class Campaign(CampaignDB):
"""
Provides sending capability to the email campaign ORM class.
"""
def __init__(self, audience_id=None, active=None, name=None):
self.audience_id = audience_id
self.active = active
self.name = name
def send(self):
print("send emails to the audience")
现在我想使用SQLAlchemy的类继承层次结构将CampaignDB
和子类Campaign
类重构为多态基。例如,我希望将CampaignDB
作为EmailCampaignDB
和PushCampaignDB
的基类。然后,我想在导入项目中分别EmailCampaignDB
和PushCampaignDB
,EmailCampaign
和PushCampaign
。不过,我仍希望能够查询Campaign
并返回EmailCampaign
和PushCampaign
的实例。
我已经多次尝试解决这个问题,但遇到了问题。特别是,session.query(Campaign).all()
没有返回任何结果,因为SQLAlchemy似乎并不认为它是一个基类。生成的SQL具有以下WHERE子句:WHERE email.campaigns.type IN (NULL)
这是我正在尝试的主旨。
class CampaignDB(Base):
"""
Note: this basic database mapper class is expected to be extended.
When sub-classing, be mindful to override mappings to other extended classes.
"""
__tablename__ = 'campaigns'
audience_id = Column(Integer, ForeignKey("audiences.id"))
active = Column(Boolean)
name = Column(Text)
type = Column(String(16))
__mapper_args__ = {
'polymorphic_on': type
}
class EmailCampaignDB(CampaignBaseDB):
__mapper_args__ = {
'polymorphic_identity': 'email'
}
class PushCampaignDB(CampaignBaseDB):
__mapper_args__ = {
'polymorphic_identity': 'push'
}
def send(self):
print("send push notifications to the audience")
class Campaign(CampaignDB):
pass
class EmailCampaign(EmailCampaignDB):
def send(self):
print("send emails to the audience")
class PushCampaign(PushCampaignDB):
def send(self):
print("send push notifications to the audience")
这可能吗?有没有更好的方法来实现这个"打包的ORM"上下文
答案 0 :(得分:0)
我设法通过改变我对问题的看法来找到一种方法来完成这项工作。我放弃了尝试创建和查询Campaign
的{{1}}子类。我还使用了Declarative API,它似乎有助于对CampaignDB
和EmailCampaignDB
进行子类化。
核心项目中的PushCampaignDB
模块:
model.email
在导入项目中对广告系列类进行子类化:
from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy import Column, Index, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy import Boolean, Integer, Text
from . import Base
class CampaignBaseDB(Base):
"""
Note: this basic database mapper class is expected to be extended.
When sub-classing, be mindful to override mappings to other extended classes.
"""
__tablename__ = 'campaign_bases'
@declared_attr
def __mapper_args__(cls):
return {
'polymorphic_on': cls.type,
}
audience_id = Column(Integer, ForeignKey("audiences.id"))
active = Column(Boolean)
name = Column(Text)
type = Column(String(16))
class EmailCampaignDB(CampaignBaseDB):
@declared_attr
def __mapper_args__(cls):
return {
'polymorphic_identity': 'email'
}
class PushCampaignDB(CampaignBaseDB):
@declared_attr
def __mapper_args__(cls):
return {
'polymorphic_identity': 'push'
}
多态查询:
from model.email import EmailCampaignDB, PushCampaignDB
class EmailCampaign(EmailCampaignDB):
def send(self):
print("send emails to the audience")
class PushCampaign(PushCampaignDB):
def send(self):
print("send push notifications to the audience")
这种方法确实会导致" SAWarning:重新分配身份的多态关联",所以我仍然觉得会有更好的方法。