Zakładamy Stół ma trzy kolumny: username
, password
i no_of_logins
.
Kiedy użytkownik próbuje się zalogować, jest sprawdzany pod kątem wpisu z zapytaniem, takim jak
user = User.query.filter_by(username=form.username.data).first()
Jeśli hasło się zgadza, idzie dalej. Chciałbym policzyć, ile razy zalogował się użytkownik. Dlatego po pomyślnym zalogowaniu chciałbym zwiększyć no_of_logins
pole i zapisać je z powrotem w tabeli użytkowników. Nie jestem pewien, jak uruchomić kwerendę aktualizującą za pomocą SqlAlchemy.
python
sqlalchemy
flask-sqlalchemy
webminal.org
źródło
źródło
user.no_of_logins += 1
może stworzyć warunki wyścigu. Zamiast tego użyjuser.no_of_logins = user.no_of_logins + 1
. Tłumaczone na SQL drugi właściwy sposób staje:SET no_of_logins = no_of_logins + 1
.user.no_of_logins = User.no_of_logins + 1
, lub innymi słowy, użyj oprzyrządowanego atrybutu modelu do stworzenia wyrażenia SQL. Twój komentarz przedstawia 2 sposoby na stworzenie takiego samego stanu wyścigu.Istnieje kilka sposobów
UPDATE
korzystania zsqlalchemy
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()
źródło
setattr(query_result, key, value)
do niektórych aktualizacji w Flask SQLAlchemy, po których następuje zatwierdzenie. Czy jest jakiś powód, aby dyskontować ten wzór?setattr(query_result, key, value)
, co jest dokładnie równoważne z pisaniemquery_result.key = value
session.query(User).filter(User.username == form.username.data).update({"no_of_logins": (User.no_of_logins +1)})
Przykłady wyjaśniające ważną kwestię w komentarzach zaakceptowanej odpowiedzi
Nie rozumiałem tego, dopóki sam się tym nie bawiłem, więc pomyślałem, że będą też inni, którzy będą zdezorientowani. Powiedzmy, że pracujesz nad użytkownikiem, którego
id == 6
i którego wno_of_logins == 30
momencie rozpoczęcia.# 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
Punkt
Odwołując się do klasy zamiast do instancji, możesz sprawić, że SQLAlchemy będzie mądrzejszy w zwiększaniu, sprawiając, że dzieje się to po stronie bazy danych zamiast po stronie Pythona. Robienie tego w ramach bazy danych jest lepsze, ponieważ jest mniej podatne na uszkodzenie danych (np. Dwóch klientów próbuje dokonać inkrementacji w tym samym czasie z wynikiem netto tylko jednej inkrementacji zamiast dwóch). Zakładam, że możliwe jest zwiększenie wartości w Pythonie, jeśli ustawisz blokady lub podniesiesz poziom izolacji, ale po co zawracać sobie głowę, jeśli nie musisz?
Zastrzeżenie
Jeśli zamierzasz zwiększać dwukrotnie za pomocą kodu, który generuje SQL
SET no_of_logins = no_of_logins + 1
, wtedy będziesz musiał zatwierdzić lub przynajmniej opróżnić między przyrostami, w przeciwnym razie otrzymasz tylko jeden przyrost w sumie:# 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
źródło
Za pomocą
user=User.query.filter_by(username=form.username.data).first()
instrukcji uzyskasz określonego użytkownika wuser
zmiennej.Teraz możesz zmienić wartość nowej zmiennej obiektowej jak
user.no_of_logins += 1
i zapisać zmianysession
metodą zatwierdzenia.źródło
Napisałem telegram bota i mam problem z aktualizacją wierszy. Użyj tego przykładu, jeśli masz Model
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')
Dlaczego używać
db.session.flush()
? Dlatego >>> SQLAlchemy: Jaka jest różnica między flush () a commit ()?źródło
flush()
zawsze jest nazywany jako część wywołaniecommit()
”