【问题标题】:SqlAlchemy auto increment composite key for every new combinationSqlAlchemy 为每个新组合自动增加复合键
【发布时间】:2021-08-02 00:27:30
【问题描述】:

我有一个场景来迭代 session_number 列以获取相关的 user_name。如果用户在我将迭代最后一个 session_number 之前创建了一个会话,但如果用户第一次创建了会话 session_number 应该从 1 开始。我试图在下面说明。现在我通过使用逻辑来处理这个问题,但尝试在 SqlAlchemy 中找到更优雅的方法。

id - user_name - session_number
1      user_1             1
2      user_1             2
3      user_2             1
4      user_1             3
5      user_2             2

这是我的表格的 python 代码。我的数据库是 PostgreSQL,我正在使用 alembic 来升级表。现在它继续迭代@​​987654327@,不管user_name

class UserSessions(db.Model):
    __tablename__ = 'user_sessions'

    id = db.Column(db.Integer, primary_key=True, unique=True)
    username = db.Column(db.String, nullable=False)
    session_number = db.Column(db.Integer, Sequence('session_number_seq', start=0, increment=1))
    created_at = db.Column(db.DateTime)
    last_edit = db.Column(db.DateTime)

    __table_args__ = (
        db.UniqueConstraint('username', 'session_number', name='_username_session_number_idx_'),
    )

我在互联网上搜索过这种情况,但这些不是我的问题。是否可以通过 SqlAlchemy/PostgreSQL 操作来实现这一点?

【问题讨论】:

  • 您可以使用混合属性,其中返回值是用户名的countdocs.sqlalchemy.org/en/14/orm/extensions/hybrid.html
  • 需要统计user_name吗?你是说 session_number 吗?
  • 在执行过程中,您真的需要session_number 的值吗?或者您只是想在以后的某个时候拥有/使用它?
  • 你需要存储这个值还是可以在检索时生成?
  • @rfkortekaas 是的,我确实这样做了。这是对实际问题的说明,但场景是相同的。

标签: python postgresql sqlalchemy alembic


【解决方案1】:

首先,我不知道使用 SqlAlchemy 或 Postgresql 或两者的组合来解决这种情况的任何“纯”解决方案。

虽然它可能不是您正在寻找的解决方案,但我希望它能给您一些想法。

如果您想计算整个表的 session_number 而不存储它,我会使用以下查询或其变体:

def get_user_sessions_with_rank():
    expr = (
        db.func.rank()
        .over(partition_by=UserSessions.username, order_by=[UserSessions.id])
        .label("session_number")
    )
    subq = db.session.query(UserSessions.id, expr).subquery("subq")
    q = (
        db.session.query(UserSessions, subq.c.session_number)
        .join(subq, UserSessions.id == subq.c.id)
        .order_by(UserSessions.id)
    )
    return q.all()

或者,我实际上会在模型中添加一个column_property,以便为UserSessions 的每个实例即时计算它。它的计算效率不高,但对于按特定用户过滤的查询,它应该足够好:

class UserSessions(db.Model):
    __tablename__ = "user_sessions"

    id = db.Column(db.Integer, primary_key=True, unique=True)
    username = db.Column(db.String, nullable=False)
    created_at = db.Column(db.DateTime)
    last_edit = db.Column(db.DateTime)

# must define this outside of the model definition because of need for aliased
US2 = db.aliased(UserSessions)
UserSessions.session_number = db.column_property(
    db.select(db.func.count(US2.id))
    .where(US2.username == UserSessions.username)
    .where(US2.id <= UserSessions.id)
    .scalar_subquery()
)

在这种情况下,当您查询UserSessions 时,将从数据库中获取session_number,而对于新创建的实例则为None

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-11
    • 2014-03-18
    • 1970-01-01
    • 2011-01-25
    • 1970-01-01
    • 2015-09-03
    • 1970-01-01
    相关资源
    最近更新 更多