python sqlalchemy-将表映射到特定的数据结构

python sqlalchemy-将表映射到特定的数据结构,python,sqlalchemy,Python,Sqlalchemy,我有一个用关系定义的表,我注意到,即使我在查询中不使用联接,仍然可以检索信息: class Employee(Base): __tablename__ = "t_employee" id = Column(Identifier(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False) jobs = relationship("EmployeeJob") roles

我有一个用关系定义的表,我注意到,即使我在查询中不使用联接,仍然可以检索信息:

class Employee(Base):
    __tablename__ = "t_employee"

    id = Column(Identifier(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
    jobs = relationship("EmployeeJob")
    roles = relationship("EmployeeRole")

class EmployeeJob(Base):
    __tablename__ = "t_employee_job"

    id = Column(Integer(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
    employee_id = Column(Integer(20), ForeignKey('t_employee.id', ondelete="CASCADE"), primary_key=True)
    job_id = Column(Integer(20), ForeignKey('t_job.id', ondelete="CASCADE"), primary_key=True)

class EmployeeRole(Base):
    __tablename__ = "t_employee_role"

    id = Column(Integer(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
    employee_id = Column(Integer(20), ForeignKey('t_employee.id', ondelete="CASCADE"), nullable=False)
    location_id = Column(Identifier(20), ForeignKey('t_location.id', ondelete="CASCADE"))
    role_id = Column(Integer(20), ForeignKey('t_role.id', ondelete="CASCADE"), nullable=False)
session.query(Employee).all()
也检索角色和作业,但通过查询每行的db来实现

关于这种情况,我有两个问题:
1.就表现而言,我想我应该自己参加。我说的对吗?
2.如何将表映射到特定的数据结构?例如,我想获得员工及其角色的列表,其中每个角色都应该由位置ID和角色ID数组表示,例如
{ID:1,jobs:[1,2,3],roles:[1,1],[1,2],[2,3]}

1)请阅读SA文档。 默认情况下,关系在第一次访问时加载。例如,在您的情况下,您可以使用,以便在同一查询中加载相关行:

qry = (session.query(Employee).
       options(joinedload(Employee.jobs)).
       options(joinedload(Employee.roles))
      ).all()
如果希望在加载员工时始终加载这些关系,可以将配置为自动加载:

class Employee(Base):
    # ...
    jobs = relationship("EmployeeJob", lazy="joined")
    roles = relationship("EmployeeRole", lazy="subquery")
2)只需创建一个从查询中提取数据结构的方法。下面这样做应该可以(使用答案第一部分中的
qry
):



另请注意:您的
EmployeeJob
表中有一个有趣的
主键
,它包括
id
列和两个
ForeignKey
列。我想你应该选择一个或另一个。

我终于找到了完成第二个问题的方法,并决定为了他人的利益回答我自己的问题:

from sqlalchemy.ext.hybrid import hybrid_property

class Employee(Base):
    __tablename__ = "t_employee"

    id = Column(Identifier(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
    _jobs = relationship("EmployeeJob", lazy="joined", cascade="all, delete, delete-orphan")
    _roles = relationship("EmployeeRole", lazy="joined", cascade="all, delete, delete-orphan")

    @hybrid_property
    def jobs(self):
        return [item.employee_id for item in self._jobs]

    @jobs.setter
    def jobs(self, value):
        self._jobs = [EmployeeJob(job_id=id) for id in value]

    @hybrid_property
    def roles(self):
        return [[item.location_id, item.role_id] for item in self._roles]

    @roles.setter
    def roles(self, value):
        self._roles = [EmployeeRole(location_id=l_id, role_id=r_id) for l_id, r_id in value]
关系中的级联是为了确保更新列表后删除孤立项,并且装饰器定义每个复杂属性的getter和setter


谢谢你给我指明了正确的方向

谢谢你,范!懒惰属性的作用就像一个符咒。。。关于第二部分,我希望此映射对保存操作也有效(这意味着我将传递{roles:[[1,1]]}进行合并,它将知道如何处理)。这可能吗?关于EmployeeJob,您是对的,外键是唯一的,但不是主要的。只需创建方法(员工类的par)来执行您用文字描述的操作。您需要根据引用对象的
id
s查找(查询)引用对象,并使用字典添加/del/update关系。我想这是可行的。这是否意味着在炼金术中没有这样做的内在能力?
from sqlalchemy.ext.hybrid import hybrid_property

class Employee(Base):
    __tablename__ = "t_employee"

    id = Column(Identifier(20), Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False)
    _jobs = relationship("EmployeeJob", lazy="joined", cascade="all, delete, delete-orphan")
    _roles = relationship("EmployeeRole", lazy="joined", cascade="all, delete, delete-orphan")

    @hybrid_property
    def jobs(self):
        return [item.employee_id for item in self._jobs]

    @jobs.setter
    def jobs(self, value):
        self._jobs = [EmployeeJob(job_id=id) for id in value]

    @hybrid_property
    def roles(self):
        return [[item.location_id, item.role_id] for item in self._roles]

    @roles.setter
    def roles(self, value):
        self._roles = [EmployeeRole(location_id=l_id, role_id=r_id) for l_id, r_id in value]