SQLAlchemy satır girişi nasıl güncellenir?


139

Varsayalım tablo üç sütun bulunur: username, passwordve no_of_logins.

Kullanıcı giriş yapmaya çalıştığında, aşağıdaki gibi bir sorgu içeren bir giriş kontrol edilir:

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

Parola eşleşirse, daha fazla ilerler. Yapmak istediğim şey, kullanıcının kaç kez oturum açtığını saymak. Bu nedenle, ne zaman başarılı bir şekilde oturum açsa, no_of_loginsalanı genişletmek ve kullanıcı tablosuna geri kaydetmek istiyorum. SqlAlchemy ile güncelleme sorgusunu nasıl çalıştıracağımdan emin değilim.

Yanıtlar:


133
user.no_of_logins += 1
session.commit()

12
stackoverflow.com/a/2334917/125507 , bunu yapmanın kötü bir yolu olduğunu söylüyor. Ayrıca satır henüz yoksa?
endolith

6
Endolith'in bağlantısına göre, user.no_of_logins += 1yarış koşulları yaratabilir. Bunun yerine kullanın user.no_of_logins = user.no_of_logins + 1. Sql çevrildi ikincisi doğru yolu haline gelir: SET no_of_logins = no_of_logins + 1.
ChaimG

5
@ChaimG Sanırım demek istediniz user.no_of_logins = User.no_of_logins + 1veya başka bir deyişle modelin enstrümantasyonlu özelliğini bir SQL ifadesi üretmek için kullanın. Yorumunuz aynı yarış koşulunu oluşturmanın 2 yolunu gösteriyor.
Ilja Everilä

2
Onlar değil. İlki, özniteliği bir SQL ifadesine ayarlar, ikincisi Python'da yerinde bir ekleme gerçekleştirir ve yine yarışı tanıtır.
Ilja Everilä

1
@jayrizzo SERİLEŞTİRİLEBİLİR işlem izolasyon düzeyine o kadar aşina değilim, ancak anladığım kadarıyla, yerinde eklemeyi kullanarak Python'da eklemenin gerçekleştirilmesine izin verecek. Bir yarış varsa, işlemlerden biri başarılı olur ve diğerleri başarısız olur ve yeniden denemesi gerekir (DB'nin yeni durumu ile). Ama SERİLEŞTİRİLEBİLİR yanlış anlamış olabilirim.
Ilja Everilä

343

UPDATEKullanmanın birkaç yolu varsqlalchemy

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

3
setattr(query_result, key, value)Flask SQLAlchemy'deki bazı güncellemeler için kullanıyorum ve ardından bir commit yapıyorum . Bu kalıbı azaltmak için herhangi bir neden var mı?
Marc

2
@datamafia: Yazmaya setattr(query_result, key, value)tamamen eşdeğer olan kullanabilirsinizquery_result.key = value
Nima Soroush

Thx @NimaSoroush, yaptığım bu ve evet eşdeğer.
Marc

8
Bu davalar arasındaki farklılıkları açıklamak mümkün mü? Teşekkürler!
Hatshepsut

1
@Hatshepsut Bugün 4 ile 1/2 arasında karşılaştığım bir fark şu adreste: groups.google.com/forum/#!topic/sqlalchemy/wGUuAy27otM
Vikas Prasad

13

Kabul edilen cevabın yorumlarındaki önemli konuyu netleştirmek için örnekler

Ben de onunla oynayana kadar anlamadım, bu yüzden kafası karışan başkalarının da olacağını düşündüm. Kimin id == 6ve kimin no_of_logins == 30ne zaman başladığınız üzerinde çalıştığınızı varsayalım.

# 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

Nokta

Örnek yerine sınıfa başvurarak, SQLAlchemy'nin artma konusunda daha akıllı olmasını ve bunun Python tarafı yerine veritabanı tarafında olmasını sağlayabilirsiniz. Veri bozulmasına karşı daha az savunmasız olduğu için veri tabanı içinde yapmak daha iyidir (örneğin, iki istemci aynı anda iki yerine yalnızca bir artım net sonucu ile artış yapmaya çalışır). Kilitleri ayarlarsanız veya izolasyon seviyesini yükseltirseniz, Python'da artış yapmanın mümkün olduğunu varsayıyorum, ama gerekmiyorsa neden zahmet edesiniz?

Bir uyarı

SQL gibi üreten bir kodla iki kez SET no_of_logins = no_of_logins + 1artıracaksanız, o zaman kaydetmeniz veya en azından artımlar arasında temizlemeniz gerekir, yoksa toplamda yalnızca bir artış elde edersiniz:

# 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

Merhaba, cevabınız için teşekkürler, bir int değişkeni yerine bir string değişkenini güncellemeye çalışıyorum, bunu nasıl yaparım? bir sqlite veritabanı kullanıyorum ve değiştirmek istediğim değişkenler bir form göndererek current_user içinde
dani bilel

1
@danibilel Oldukça kapsamlı olan belgelere bakın. Eğiticinin bu bölümü, dize alanlarının güncellenmesinin üzerinden geçer: docs.sqlalchemy.org/en/13/orm/… . Aksi takdirde, özellikle neye takıldığınızı gösteren yeni bir soru göndermenizi öneririm.
MarredCheese

Bağlantı için teşekkürler, bütün günü araştırarak geçirdikten sonra, sorunumun db.session.commit () ile ilgili olduğunu biliyorum, konsoldaki değişiklikleri gerektiği gibi sürdürmüyor, benzer sorular buldum ama cevap vermedim benim için çalış, gerçek web uygulamasında daha da kötü! Değişiklikler hiç kaydedilmedi, uzun yorum için üzgünüm ama web sitesinin politikası nedeniyle bir soru ekleyemiyorum, herhangi bir yardım memnuniyetle karşılanacaktır.
dani bilel

4

İfade yardımı ile user=User.query.filter_by(username=form.username.data).first(), belirtilen kullanıcıyı userdeğişkende alacaksınız .

Artık yeni nesne değişkeninin değerini değiştirebilir ve user.no_of_logins += 1değişiklikleri session's commit yöntemi ile kaydedebilirsiniz .


2

Telgraf botu yazdım ve güncelleme satırlarıyla ilgili bazı problemlerim var. Modeliniz varsa bu örneği kullanın

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

Neden kullanmalı db.session.flush()? Bu yüzden >>> SQLAlchemy: flush () ve commit () arasındaki fark nedir?


7
Floş, commit'den hemen önce tamamen gereksizdir. Bir commit her zaman dolaylı olarak boşaltılır. flush()commit()
Bağlandığınız Soru / Cevapta da söylendiği
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.