テーブルには、username
、password
、およびno_of_logins
の3つの列があるとします。
ユーザーがログインしようとすると、次のようなクエリでエントリがチェックされます
user=User.query.filter_by(username=form.username.data).first()
パスワードが一致する場合、彼はさらに先へ進みます。私がやりたいのは、ユーザーが何回ログインしたかを数えることです。したがって、彼が正常にログインするたびに、no_of_logins
フィールドをインクリメントし、ユーザーテーブルに戻します。 SqlAlchemyで更新クエリを実行する方法がわかりません。
user.no_of_logins += 1
session.commit()
UPDATE
を使用してsqlalchemy
を使用する方法はいくつかあります
1) user.no_of_logins += 1
session.commit()
2) session.query().\
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
のような新しいオブジェクト変数の値を変更し、session
のcommitメソッドで変更を保存できます。
自分で試してみるまで理解できなかったので、混乱する人もいると思いました。開始時に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
インスタンスの代わりにクラスを参照することで、SQLAlchemyがインクリメントについてよりスマートになり、Python側ではなくデータベース側で発生するようになります。データベース内で実行すると、データ破損に対する脆弱性が低くなるため(たとえば、2つのクライアントが同時に増分しようとすると、最終的に2つではなく1つしか増分されません)、データベース内で行う方が適切です。ロックを設定したり、分離レベルを上げたりすれば、Pythonでインクリメントすることが可能だと思いますが、なぜそうする必要がないのでしょうか?
SET no_of_logins = no_of_logins + 1
のようなSQLを生成するコードを介して2回インクリメントする場合は、コミットするか、少なくともインクリメント間でフラッシュする必要があります。
# 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
私は電報ボットを作成しましたが、更新行に問題があります。モデルがある場合は、この例を使用してください
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()の違いは何ですか?