假设表有三列:用户名、密码和no_of_logins。

当用户尝试登录时,它会检查带有类似查询的条目

user = User.query.filter_by(username=form.username.data).first()

如果密码匹配,则继续执行。我想做的是计算用户登录的次数。因此,每当他成功登录时,我希望增加no_of_logins字段并将其存储回用户表。我不知道如何运行更新查询与SqlAlchemy。


当前回答

因为这是谷歌上出现的第一个结果,所以我想分享一种使用SQLAlchemy更新行的更可伸缩的方法。它是基于之前的答案,我目前使用它与一个接口,允许我做table.update(**kwargs)通过我所有的CRUD表。

class User(Base):

    __tablename__ = 'users'

    user_id = Column(Integer, primary_key=True)
    first_name = Column(String)
    last_name = Column(String)

    def __init__(self, first_name: str, last_name: str, user_id: int = None):
        self.firtst_name = first_name
        self.last_name = last_name
        self.user_id = user_id

    def update(self, first_name: str, last_name: str, user_id: int = None, **kwargs):
        self.firtst_name = first_name
        self.last_name = last_name
        self.user_id = user_id
        
    def __repr__(self):
        return self.firtst_name

更新方法内置于ORM表声明本身。这样表就知道该如何更新自己。这可能对将来的UPSERT操作有用。

with new_session() as post_session:
    post_data = request.form.to_dict(flat=False)
    client = Client.query.filter_by(id=post_data["id"]).first()
    client.update(**post_data)
    post_session.add(client)

实际的更新就变得非常简单。从这里进行概括也很容易。

其他回答

举例说明已接受的回答中的重要问题

直到我自己玩了一下,我才明白它的意思,所以我想其他人也会感到困惑。假设您开始时正在处理id == 6且no_of_logins == 30的用户。

# 1 (bad)
user.no_of_logins += 1
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 2 (bad)
user.no_of_logins = user.no_of_logins + 1
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 3 (bad)
setattr(user, 'no_of_logins', user.no_of_logins + 1)
# result: UPDATE user SET no_of_logins = 31 WHERE user.id = 6

# 4 (ok)
user.no_of_logins = User.no_of_logins + 1
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

# 5 (ok)
setattr(user, 'no_of_logins', User.no_of_logins + 1)
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

这一点

By referencing the class instead of the instance, you can get SQLAlchemy to be smarter about incrementing, getting it to happen on the database side instead of the Python side. Doing it within the database is better since it's less vulnerable to data corruption (e.g. two clients attempt to increment at the same time with a net result of only one increment instead of two). I assume it's possible to do the incrementing in Python if you set locks or bump up the isolation level, but why bother if you don't have to?

一个警告

如果你要通过产生SET no_of_logins = no_of_logins + 1这样SQL语句的代码增加两次,那么你需要提交或至少在增量之间刷新,否则你总共只会得到一次增量:

# 6 (bad)
user.no_of_logins = User.no_of_logins + 1
user.no_of_logins = User.no_of_logins + 1
session.commit()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

# 7 (ok)
user.no_of_logins = User.no_of_logins + 1
session.flush()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6
user.no_of_logins = User.no_of_logins + 1
session.commit()
# result: UPDATE user SET no_of_logins = no_of_logins + 1 WHERE user.id = 6

有几种使用sqlalchemy进行UPDATE的方法

1) user.no_of_logins += 1
   session.commit()
   
2) session.query(User).\
       filter(User.username == form.username.data).\
       update({'no_of_logins': User.no_of_logins + 1})
   session.commit()

3) conn = engine.connect()
   stmt = User.update().\
       values(no_of_logins=User.no_of_logins + 1).\
       where(User.username == form.username.data)
   conn.execute(stmt)

4) setattr(user, 'no_of_logins', user.no_of_logins + 1)
   session.commit()

在user= user .query.filter_by(username=form.username.data).first()语句的帮助下,您将在user变量中获得指定的用户。

现在您可以像user一样更改新对象变量的值。No_of_logins += 1,并使用会话的commit方法保存更改。

user.no_of_logins += 1
session.commit()

我写电报机器人,有一些问题更新行。 使用这个例子,如果你有模型

def update_state(chat_id, state):
    try:
        value = Users.query.filter(Users.chat_id == str(chat_id)).first()
        value.state = str(state)
        db.session.flush()
        db.session.commit()
        #db.session.close()
    except:
        print('Error in def update_state')

为什么使用db.session.flush()?这就是为什么>>> SQLAlchemy: flush()和commit()之间有什么区别?