使用SQLAlchemy处理项目时,我试图使用我认为的组合模式。我有一类“所有者”对象;我将一些功能封装在组件类中,并通过为组件分配组件为所有者提供不同的功能。所有者和组件都具有需要序列化的状态,因此它们都是SQLAlchemy对象。这是一个简单的例子(linked for readability):
class Employee(DeclarativeBase):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String)
def __init__(self, name):
self.name = name
class SalesRole(DeclarativeBase):
__tablename__ = 'sales_role'
id = Column(Integer, primary_key=True)
employee_id = Column(Integer, ForeignKey('employee.id'))
employee = relationship(
'Employee',
backref=backref('sales_role', uselist=False)
)
def __init__(self, employee):
self.employee = employee
self.total_sales = 0
def __repr__(self):
return "<SalesRole(employee='%s')>" % self.employee.name
# Sales-specific data and behavior
total_sales = Column(Float)
class CustomerSupportRole(DeclarativeBase):
__tablename__ = 'support_role'
id = Column(Integer, primary_key=True)
employee_id = Column(Integer, ForeignKey('employee.id'))
employee = relationship(
'Employee',
backref=backref('support_role', uselist=False)
)
def __init__(self, employee):
self.employee = employee
self.tickets_resolved = 0
def __repr__(self):
return "<CustomerSupportRole(employee='%s')>" % self.employee.name
# Support-specific data and behavior
tickets_resolved = Column(Integer)
我希望能够在所有者类上定义一个属性,该属性返回包含已分配给所有者的所有此类组件的集合(无论何种类型),即
# Define an Employee object bob and assign it some roles
>>> bob.roles
[<SalesRole(employee='Bob')>, <CustomerSupportRole(employee='Bob')>]
我想在没有硬编码对所有者类可以存在的组件类型的任何引用的情况下完成此操作 - 我想在不改变其他任何地方的代码的情况下定义新组件。
我可以使用sqlalchemy-utils中的generic_relationship
将所有者实例映射到其组件的中间表或多或少地完成此操作。不幸的是,generic_relationship
切断了SQLAlchemy对子对象的自动级联。
我在其他地方尝试过的另一种方法是使用SQLAlchemy的事件框架来监听针对所有者类('mapper_configured'
事件)的关系映射。组件将从自身定义backref到所有者类,并使用info
参数设置表示此关系的任意标志,作为指向我们希望通过此集合提供的组件之一。注册用于捕获映射事件的函数将测试此标志,并假设构建包含这些关系的集合,但我们永远无法弄清楚如何使其工作。
bob.roles.append(SalesmanRole())
。这将非常酷,但只是一个属性作为只读的可迭代视图就够了。bob.sales_role
。如果他们这样做就没关系,但我认为该集合对我来说实际上更重要。有没有办法让这项工作?或者我应该采取不同的方法 - 随意告诉我这听起来像一个XY问题。
答案 0 :(得分:0)
答案是我怀疑的,但并不是很难找到:class inheritance。简单,优雅,完成我想要的一切。
class Role(DeclarativeBase):
__tablename__ = 'role'
id = Column(Integer, primary_key=True)
role_type = Column(String)
employee_id = Column(Integer, ForeignKey('employee.id'))
employee = relationship('Employee', backref='roles')
__mapper_args__ = {
'polymorphic_identity': 'employee',
'polymorphic_on': role_type
}
class SalesRole(Role):
__tablename__ = 'sales_role'
id = Column(Integer, ForeignKey('role.id'), primary_key=True)
__mapper_args__ = {
'polymorphic_identity': 'sales_role'
}
# Sales-specific attributes, etc.
class CustomerSupportRole(Role):
__tablename__ = 'support_role'
id = Column(Integer, ForeignKey('role.id'), primary_key=True)
__mapper_args__ = {
'polymorphic_identity': 'support_role'
}
# Support-specific attributes, etc.