python - 如何使用基于 SQLAlchemy 中角色的判别器正确建模连接表继承

标签 python orm sqlalchemy data-modeling

是否可以指定另一个表中的鉴别器列?如何使用声明式做到这一点?

原因是我有一个连接表继承

class User(Base):
    id = Column(...)

class Customer(User):
    customer_id = Column('id', ...)

class Mechanic(User):
    mechanic_id = Column('id', ...)

class Role(Base):
    id = Column(..)

但想要根据用户所拥有的角色进行歧视。用户可以具有买方角色或卖方角色或两者兼而有之。

这是模拟此场景的正确方法吗?

请注意,还有买方特定数据和卖方特定数据,这就是我使用连接表继承的原因。

最佳答案

这是一种实现特定结果的笨拙且低效的方法,如果目标用户上存在多个角色,该方法也会失败:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

role_to_user = Table('role_to_user', Base.metadata,
    Column('role_id', Integer, ForeignKey('role.id'), primary_key=True),
    Column('user_id', Integer, ForeignKey('user.id'), primary_key=True),
)

class Role(Base):
    __tablename__ = 'role'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)

    discrim = select([Role.name])
    discrim_col = discrim.label("foo")
    type = column_property(discrim_col)
    roles = relationship("Role", secondary=role_to_user)
    __mapper_args__ = {'polymorphic_on': discrim_col}

User.discrim.append_whereclause(Role.id==role_to_user.c.role_id)
User.discrim.append_whereclause(role_to_user.c.user_id==User.id)

class Customer(User):
    __tablename__ = 'customer'
    id = Column(Integer, ForeignKey(User.id), primary_key=True)
    __mapper_args__ = {'polymorphic_identity':'customer'}

class Mechanic(User):
    __tablename__ = 'mechanic'
    id = Column(Integer, ForeignKey(User.id), primary_key=True)

    __mapper_args__ = {'polymorphic_identity':'mechanic'}

e = create_engine('sqlite://', echo=True)

Base.metadata.create_all(e)

s = Session(e)

m, c = Role(name='mechanic'), Role(name='customer')
s.add_all([m, c])
s.add_all([Mechanic(roles=[m]), Customer(roles=[c])])
s.commit()

print Session(e).query(User).all()

接下来,如果我遇到基于零个或多个角色分配行为的问题,我实际上会这样做 - 我会将行为放入角色中,而不是角色的所有者中:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    roles = relationship("Role", secondary= Table(
                    'role_to_user', Base.metadata,
                    Column('role_id', Integer, 
                            ForeignKey('role.id'), 
                            primary_key=True),
                    Column('user_id', Integer, 
                            ForeignKey('user.id'), 
                            primary_key=True),
                    ),
                    lazy="subquery"
                )

    def operate_on_roles(self):
        for role in self.roles:
            role.operate(self)

class Role(Base):
    __tablename__ = 'role'
    id = Column(Integer, primary_key=True)
    type = Column(String, nullable=False)
    __mapper_args__ = {'polymorphic_on': type}

class CustomerRole(Role):
    __tablename__ = 'customer'
    id = Column(Integer, ForeignKey(Role.id), primary_key=True)
    __mapper_args__ = {'polymorphic_identity':'customer'}

    def operate(self, user):
        print "user %s getting my car fixed!" % user.name

class MechanicRole(Role):
    __tablename__ = 'mechanic'
    id = Column(Integer, ForeignKey(Role.id), primary_key=True)
    __mapper_args__ = {'polymorphic_identity':'mechanic'}

    def operate(self, user):
        print "user %s fixing cars!" % user.name

e = create_engine('sqlite://', echo=True)

Base.metadata.create_all(e)

s = Session(e)

m, c = MechanicRole(), CustomerRole()
s.add_all([m, c])
s.add_all([
        User(name='u1', roles=[m, c]),
        User(name='u2', roles=[c]),
        User(name='u3', roles=[m]),
    ])
s.commit()

for user in s.query(User):
    user.operate_on_roles()

第二个示例产生输出:

user u1 fixing cars!
user u1 getting my car fixed!
user u2 getting my car fixed!
user u3 fixing cars!

正如您所看到的,第二个示例清晰有效,而第一个示例只是一个思想实验。

关于python - 如何使用基于 SQLAlchemy 中角色的判别器正确建模连接表继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6146795/

相关文章:

在 __table_args__ 中使用 CheckConstraint 的 Flask-SQLAlchemy 混合导致错误

flask 。 sqlalchemy.exc.InterfaceError : <app. models.Menu 对象位于 0x7f287026dd10>

python - 从 sqlalchemy Session 获取一个 mysql 线程 id

python - 如何使 'while' 循环将循环条件的结果打印到单行(串联)中?

java - 使用 JPQL 计算关联对象的正确方法

java - Hibernate 生成预定义的实体标识符

java - 是否可以获取 Hibernate sqlRestriction 的连接表的 SQL 别名?

python - 使用Python解析特定的网站(XML)并保存到mysql

python - 方法 set_seq1 和 set_seq2 的工作,difflib python

python - 在 Python 中将两个数组 append 在一起