SQLAlchemy:关系字段值

2024-09-28 21:59:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我有三个[MySQL]表:Person、Role、PersonRole

class Person(Base):

    __tablename__ = 'people'

    id = Column(INTEGER(unsigned=True), primary_key=True)
    full_name = Column(String(120), nullable=False)
    email = Column(String(128))
    username = Column(String(50))
    last_modified = Column(TIMESTAMP, nullable=False,
                           server_default=text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
    created = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'))

    roles = relationship('Role',
                         secondary='person_role',
                         primaryjoin="and_(Person.id==PersonRole.person_id,"
                                     "Role.active==True,"
                                     "PersonRole.active==True)",
                         back_populates='people')

    def __repr__(self):
        """String representation."""
        return '''<Person(id='%s', full_name='%s')>''' % (
            str(self.id), str(self.full_name)
        )


class Role(Base):

    __tablename__ = 'role'

    id = Column(INTEGER(unsigned=True), Sequence('role_id_seq'), primary_key=True)
    role_name = Column(String(16))
    active = Column(Boolean, default=True)
    last_modified = Column(TIMESTAMP, nullable=False,
                           server_default=text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
    created = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'))

    users = relationship('Person',
                         secondary='person_role',
                         primaryjoin="and_(Role.id==PersonRole.role_id,"
                                     "Role.active==True,"
                                     "PersonRole.active==True)",
                         back_populates='roles')

    def __repr__(self):
        """String representation."""
        return '''<Role(role_id='%s', role_name='%s')>''' % (
            str(self.role_id), str(self.role_name)
        )


class PersonRole(Base):
    __tablename__ = 'person_role'

    ds_id = Column(INTEGER(unsigned=True),
                   ForeignKey('person.id'), primary_key=True)
    role_id = Column(INTEGER(unsigned=True),
                     ForeignKey('role.id'), primary_key=True)
    active = Column(Boolean, default=True)
    last_modified = Column(TIMESTAMP, nullable=False,
                           server_default=text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))
    created = Column(TIMESTAMP,
                     server_default=text('CURRENT_TIMESTAMP'))

找回这样的人:

…会话设置为s。。。在

^{pr2}$

列出他们的角色:

for role in person.roles:
    print(role.id, role.role_name, role.active)

现在,在每个表中都有一个active列。这是为了跟踪[shocker]的活动状态,因为我们不想从表中删除数据,而只是保持它的状态。现在谈谈两个问题,这两个问题使我无法完全使用SQLAlchemy,并让我手动编写和执行SQL-

  1. 但最终循环中的active部分显示role.active的活动状态,而不是实际关系person_role.active的活动状态。在
  2. 删除角色将删除关系行,而不是执行所需的操作person_role.active = 0
  3. 即使我停用了关系,再次添加它也会引起Duplicate Key错误。在

有没有一种合理有效的方法可以在不重组数据的情况下实现这一目标?在


编辑以进一步澄清:

本例中的两个主要表是person和{}。Person是存放用户的主表。PersonRole以person.idrole.id的形式持有一个人实际拥有的角色。角色表只是角色定义的查找表(用于获取名称)。在

我想我想要的是一种拦截ORM如何实际添加/删除数据的方法。添加应该[或多或少]执行一个“upsert”,删除操作基本上应该运行一个更新查询,比如:update person_role set active = 0 where person_id = %s and role_id = %s。在

我读过很多文献,但往往对术语迷茫。:秒


Tags: nameidtruedefaultstringservercolumncurrent
1条回答
网友
1楼 · 发布于 2024-09-28 21:59:20

我不确定我完全理解你的问题,但让我试着帮助你:

1)这是我最容易混淆的一个:person.roles映射到Role实体的集合。这不是你所期望的吗?在

2,3)您已经在Person和Role之间建立了一个关系,使用PersonRole作为辅助。停用表示将PersonRole.status设置为inactive,而不是将其删除。再次尝试添加它将显示Duplicate Key错误!在

我想您应该运行一个查询,通过ds_idrole_id加载一个PersonRole实体,将其状态更新为active并持久化更改。我知道有时候执行这项工作可能很乏味,所以也许一个不需要移动数据的直接解决方案是将Person和{}映射到PersonRole。因此,尽管有Person.roles,但您仍将拥有Person.personRoles,因此您可以访问PersonRole实体,并可以设置其状态。在

当然,这是一个非常直接的解决办法。SQLAlchemy的功能非常强大,所以您可以拦截个人角色删除并自定义其行为以将PersonRole设置为不活动。您可能还想在文档中阅读更多关于cascading的内容。在

希望我能澄清一下:)

相关问题 更多 >