如何在SQLAlchemy中增加一个计数器

bod*_*ydo 33 python sqlalchemy

假设我有一个表tags,其中有一个字段count,表示items已使用给定标签标记了多少.

在使用现有标记添加新项目后,如何在SQLAlchemy中增加此计数器?

使用纯SQL我会执行以下操作:

INSERT INTO `items` VALUES (...)
UPDATE `tags` SET count=count+1 WHERE tag_id=5
Run Code Online (Sandbox Code Playgroud)

但是我如何count=count+1在SQLAlchemy中表达?

谢谢,Boda Cydo.

tux*_*21b 54

如果你有类似的东西:

mytable = Table('mytable', db.metadata,
    Column('id', db.Integer, primary_key=True),
    Column('counter', db.Integer)
)
Run Code Online (Sandbox Code Playgroud)

你可以增加这样的字段:

m = mytable.query.first()
m.counter = mytable.c.counter + 1
Run Code Online (Sandbox Code Playgroud)

或者,如果您有一些映射模型,您可以选择:

m = Model.query.first()
m.counter = Model.counter + 1
Run Code Online (Sandbox Code Playgroud)

两个版本都将返回您要求的sql语句.但是如果你不包括该列并且只是写m.counter += 1,那么新值将在Python中计算(并且可能发生竞争条件).因此,总是在此类计数器查询中包含上面两个示例中所示的列.

此致,
Christoph

  • 如果你在Python中增加实际值(例如int类型3),你将获得一个新的整数(例如4).如果有更多客户端同时执行此操作,则可能会丢失一些更新.SqlAlchemy的列类型有一个重载的__add__运算符,因此写入"column + 1"将导致一个对象告诉数据库(而不是Python!)将列递增一. (5认同)
  • 不。我向您展示的两个版本完全相同(一个使用映射对象,另一个使用表)。但是带有 `+=` 的第三个语句将导致 `SET counter=4` 而不是 `SET counter=counter+1`。所以你不应该使用第三个 `+=` 版本。 (3认同)
  • 谢谢.但是你能更多地解释一下种族状况吗?我是否理解正确,第一个版本比第二个版本更安全? (2认同)
  • 您能解释一下mytable.c.counter的来源吗?这是我不熟悉的语法,似乎它引用的是表定义而不是所选的行'm'...所以我不清楚数学的工作原理。 (2认同)
  • 关于竞争条件的一个很好的观点——这是一个很容易出错的观点。 (2认同)

Ant*_*sma 30

如果您使用的是SQL层,则可以在update语句中使用任意SQL表达式:

conn.execute(tags.update(tags.c.tag_id == 5).values(count=tags.c.count + 1))
Run Code Online (Sandbox Code Playgroud)

ORM Query对象还有一个更新方法:

session.query(Tag).filter_by(tag_id=5).update({'count': Tag.count + 1})
Run Code Online (Sandbox Code Playgroud)

ORM版本非常智能,如果它在会话中,也会更新对象本身的count属性.