如何在SQLAlchemy中增加计数器

58 投票
3 回答
40901 浏览
提问于 2025-04-15 19:43

假设我有一个叫做 tags 的表,这个表里有一个字段 count,它表示有多少个 items 被标记了这个标签。

那么在我添加一个带有已有标签的新项目后,如何在 SQLAlchemy 中增加这个计数呢?

如果用普通的 SQL,我会这样做:

INSERT INTO `items` VALUES (...)
UPDATE `tags` SET count=count+1 WHERE tag_id=5

但是我该如何在 SQLAlchemy 中表示 count=count+1 呢?

3 个回答

1

关于@Leon的评论,你可以稍微改写一下代码,以避免竞争条件。

async def inc_counter(id_: int):
    query = items.update(items.c.id==id_)
    return await db.execute(query, values={'counter': items.c.counter + 1})

另外,如果你是以类的方式创建表格,你需要访问table这个属性:

from sqlalchemy import update

async def inc_counter(id_: int):
    query = update(Items).filter(Items.id==id_)
    return await db.execute(query, values={'counter': Items.__table__.c.counter + 1})
55

如果你在使用SQL层,那么你可以在更新语句中使用任意的SQL表达式:

conn.execute(tags.update(tags.c.tag_id == 5).values(count=tags.c.count + 1))

ORM查询对象也有一个更新的方法:

session.query(Tag).filter_by(tag_id=5).update({'count': Tag.count + 1})

这个ORM版本很聪明,如果对象在会话中,它还会自动更新对象本身的计数属性。

94

如果你有类似这样的东西:

mytable = Table('mytable', db.metadata,
    Column('id', db.Integer, primary_key=True),
    Column('counter', db.Integer)
)

你可以像这样增加字段的值:

m = mytable.query.first()
m.counter = mytable.c.counter + 1

或者,如果你有一些映射的模型,你也可以这样写:

m = Model.query.first()
m.counter = Model.counter + 1

这两种写法都会返回你想要的SQL语句。但是,如果你不写列名,直接写 m.counter += 1,那么新的值会在Python中计算(这可能会导致竞争条件的问题)。所以在这种计数器查询中,记得像上面两个例子那样总是包含列名。

撰写回答