如何更新SQLAlchemy行条目



假设表有三列:usernamepasswordno_of_logins

当用户尝试登录时,会使用类似的查询来检查条目

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

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

有几种方法可以使用SQLAlchemy进行更新:

  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.no_of_logins += 1
session.commit()

澄清公认答案评论中重要问题的示例

直到我自己摆弄它,我才明白,所以我想也会有其他人感到困惑。假设您正在处理其id == 6no_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

要点

通过引用类而不是实例,您可以让SQLAlchemy在增量方面更聪明,让它发生在数据库端,而不是Python端。在数据库中执行此操作会更好,因为它不太容易受到数据损坏的影响(例如,两个客户端试图同时增量,最终结果只有一个增量而不是两个)。我认为,如果设置了锁或提高了隔离级别,就可以在Python中进行增量,但如果不必这样做,为什么还要麻烦呢?

警告

如果您要通过生成类似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

我写了telegram bot,在更新行时遇到了一些问题。使用此示例,如果您有型号

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:What';flush()和commit()有什么区别?

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

现在,您可以更改新对象变量(如user.no_of_logins += 1)的值,并使用session的commit方法保存更改。

如果您将fastapisqlachemy一起使用,则可以使用SqlAlchemy核心更新行,如下所示(适用于其他python sqlalchemy代码):

  • 更新完整记录:
from sqlalchemy import update as sqlalchemy_update
 query = sqlalchemy_update(Evaluation).where(
            Evaluation.id == id).values(**evaluation.dict())
        await db.execute(query)
        await db.commit()

evaluation是型号Evaluationpydantic模式

  • PATCH(更新行的特定列):使用对象将要更新的列包装为值示例:
     query = sqlalchemy_update(DimensionsEvaluation).where(DimensionsEvaluation.evaluation_id == evluation_id).where(
                DimensionsEvaluation.dimension_id == id).values({
                    "selected": True
                })
            await db.execute(query)

因为这是谷歌上出现的第一个结果,我想与SQLAlchemy分享一种更可扩展的更新行的方法。它基于前面的答案,我目前使用它和一个接口,允许我在所有CRUD表中执行table.update(**kwargs)。

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

update方法内置在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)

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

相关内容

  • 没有找到相关文章

最新更新