Cum se actualizează intrarea rândului SQLAlchemy? (Programare, Python, Sqlalchemy, Flask Sqlalchemy)

webminal.org a intrebat.

Să presupunem că tabelul are trei coloane: username, , password și no_of_logins.

Când utilizatorul încearcă să se conecteze, se verifică dacă există o intrare cu o interogare de tipul

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

Dacă parola se potrivește, el merge mai departe. Ceea ce aș dori să fac este să număr de câte ori s-a logat utilizatorul. Astfel, de fiecare dată când acesta se conectează cu succes, aș dori să măresc numărul no_of_logins și să îl stochez înapoi în tabelul de utilizatori. Nu sunt sigur cum să execut interogarea de actualizare cu SqlAlchemy.

5 răspunsuri
Denis
user.no_of_logins += 1
session.commit()

Comentarii

    17

  • stackoverflow.com/a/2334917/125507 spune că acesta este un mod greșit de a face acest lucru. De asemenea, ce se întâmplă dacă rândul nu există încă? –  > Por endolith.
  • Conform linkului lui endolith, user.no_of_logins += 1 poate crea condiții de concurență. În schimb, utilizați user.no_of_logins = user.no_of_logins + 1. Tradus în sql, acest ultim mod corect devine: SET no_of_logins = no_of_logins + 1. –  > Por ChaimG.
  • @ChaimG Cred că ai vrut să spui user.no_of_logins = User.no_of_logins + 1, , sau, cu alte cuvinte, utilizați atributul instrumentat al modelului pentru a produce o expresie SQL. Așa cum este, comentariul dvs. afișează 2 moduri de a produce aceeași condiție de rasă. –  > Por Ilja Everilä.
  • Nu sunt. Primul setează atributul într-o expresie SQL, al doilea efectuează o adăugare in-place în Python și introduce din nou cursa. –  > Por Ilja Everilä.
  • @jayrizzo Nu sunt atât de familiarizat cu nivelul de izolare a tranzacției SERIALIZABLE, dar din câte înțeleg eu ar permite efectuarea adunării în Python folosind adunarea in-place. Dacă există o cursă, una dintre tranzacții va reuși atunci, iar celelalte vor eșua și vor trebui să reîncerce (cu noua stare a BD). Dar s-ar putea să fi înțeles greșit SERIALIZABLE. –  > Por Ilja Everilä.
Nima Soroush

Există mai multe modalități de a UPDATE utilizare 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()

Comentarii

  • Eu folosesc setattr(query_result, key, value) pentru unele actualizări în Flask SQLAlchemy urmate de o confirmare. Vreun motiv pentru a renunța la acest model? –  > Por Marc.
  • @datamafia: Puteți utiliza setattr(query_result, key, value), , ceea ce este exact echivalent cu scrierea query_result.key = value –  > Por Nima Soroush.
  • Este posibil să se explice diferențele dintre aceste cazuri? Mulțumesc! –  > Por Hatshepsut.
  • @Hatshepsut O diferență pe care am întâlnit-o astăzi între 4 și 1/2 este la: groups.google.com/forum/#!topic/sqlalchemy/wGUuAy27otM –  > Por Vikas Prasad.
  • punctul numărul 2 eșuează dacă nu veți specifica obiectul de clasă în interiorul query(). Adică, interogarea finală este session.query(User).filter(User.username == form.username.data).update({"no_of_logins": (User.no_of_logins +1)}) –  > Por venkat.
MarredCheese

Exemple pentru a clarifica problema importantă în comentariile răspunsului acceptat

Nu am înțeles până nu m-am jucat eu însumi cu ea, așa că m-am gândit că vor fi și alții care sunt confuzi. Să zicem că lucrați la utilizatorul al cărui id == 6 și al cărui no_of_logins == 30 atunci când începeți.

# 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

Punctul

Făcând referire la clasă în loc de instanță, puteți face ca SQLAlchemy să fie mai inteligent în ceea ce privește incrementarea, făcându-l să se întâmple pe partea de bază de date în loc de partea Python. Este mai bine să o faceți în cadrul bazei de date, deoarece este mai puțin vulnerabilă la coruperea datelor (de exemplu, doi clienți încearcă să mărească în același timp cu un rezultat net de o singură creștere în loc de două). Presupun că este posibil să se facă incrementarea în Python dacă setați încuietori sau creșteți nivelul de izolare, dar de ce să vă deranjați dacă nu este necesar?

Un avertisment

Dacă aveți de gând să incrementați de două ori prin intermediul unui cod care produce SQL de tipul SET no_of_logins = no_of_logins + 1, , atunci va trebui să faceți o confirmare sau cel puțin o curățare între incrementări, altfel veți obține doar o singură incrementare în total:

# 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

Comentarii

  • Bună ziua, vă mulțumesc pentru răspuns, în loc de o variabilă int încerc să actualizez o variabilă string, cum fac asta? Folosesc o bază de date sqlite și variabilele pe care vreau să le schimb sunt în current_user, prin trimiterea unui formular –  > Por dani bilel.
  • @danibilel Verifică documentația, care este destul de completă. Această parte a tutorialului se ocupă de actualizarea câmpurilor de tip șir de caractere: docs.sqlalchemy.org/en/13/orm/…. În caz contrar, vă sugerez să postați o nouă întrebare în care să arătați la ce anume v-ați blocat. –  > Por MarredCheese.
  • Mulțumesc pentru link, după ce am petrecut întreaga zi căutând, știu că problema mea este cu db.session.commit(), nu persistă modificările în consolă așa cum ar trebui, am găsit întrebări similare, dar răspunsurile furnizate nu au funcționat pentru mine, în aplicația web reală este chiar mai rău! modificările nu sunt salvate deloc, îmi pare rău pentru comentariul lung, dar nu pot adăuga o întrebare din cauza politicii site-ului, orice ajutor ar fi apreciat. –  > Por dani bilel.
Nilesh

Cu ajutorul user=User.query.filter_by(username=form.username.data).first() statement veți obține utilizatorul specificat în user variabilă.

Acum puteți modifica valoarea noii variabile obiect, cum ar fi user.no_of_logins += 1 și să salvați modificările cu ajutorul comenzii session‘s commit.

Andrew Lutsyuk

Am scris telegram bot, și am o problemă cu rândurile de actualizare. Folosiți acest exemplu, dacă aveți modelul

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')

De ce să folosiți db.session.flush()? De aceea >>> SQLAlchemy: Care este diferența dintre flush() și commit()?

Comentarii

  • Flush este complet redundant chiar înainte de commit. Un commit face întotdeauna în mod implicit un flush. Acest lucru este menționat în întrebarea și răspunsul la care ați făcut referire: „flush() este întotdeauna apelat ca parte a unui apel la commit()” –  > Por Ilja Everilä.