sqlalchemy floş () ve eklenen kimlik?


114

Bunun gibi bir şey yapmak istiyorum:

f = Foo(bar='x')
session.add(f)
session.flush()

# do additional queries using f.id before commit()
print f.id # should be not None

session.commit()

Ama f.idolan Noneben denemek zaman. Bunu nasıl çalıştırabilirim?


2
SA motorunu ile echo=Truebaşlatabilir ve yıkama anında hangi SQL'in çalıştırıldığını görebilir misiniz? Ne açıklamak gerekir çalışmak ve size id verir ancak olabilir f.id sonuçlanır Yok olma dair bazı başka sorun var.
Pavel Repin

Yanıtlar:


63

Örnek kodunuz olduğu gibi çalışmalıdır. SQLAlchemy f.id, otomatik olarak oluşturulmuş bir birincil anahtar sütunu varsayarak, için bir değer sağlamalıdır . Birincil anahtar öznitelikleri, flush()oluşturuldukları anda işlem içinde hemen doldurulur ve herhangi bir çağrıya gerek yoktur commit(). Yani buradaki cevap aşağıdakilerden biri veya birkaçında yatıyor:

  1. Haritanızın ayrıntıları
  2. Kullanımda olan arka uçta tuhaf tuhaflıklar varsa (örneğin, SQLite bir bileşik birincil anahtar için tamsayı değerleri oluşturmaz)
  3. Yankıyı açtığınızda yayılan SQL ne diyor?

1
Haklısınız, kabukta hızlı bir kontrol, birincil anahtar alanını bir değerle doldurduğunu gösterir. Pratikte neden işe yaramadığını araştırmam gerekecek.
Eloff

3
"Örnek kodunuz bir değer sağlıyor olmalı", "sahip olduğunuz kodun olduğu gibi çalışmış olması gerekir" yerine "ilk etapta id için bir değer vermiş olmalısınız" dediğiniz gibi geliyor. Sadece üçüncü okumadan sonra birincisinden ziyade ikincisini kastettiğini bana anladım. Açıklar mısın
stokastik

126

Az önce aynı problemle karşılaştım ve test ettikten sonra bu cevaplardan HİÇBİRİNİN yeterli olmadığını buldum.

Şu anda veya sqlalchemy .6+ olarak çok basit bir çözüm var (bunun önceki sürümde var olup olmadığını bilmiyorum, ancak var olduğunu tahmin ediyorum):

session.refresh ()

Yani kodunuz şuna benzer:

f = Foo(bar=x)
session.add(f)
session.flush()
# At this point, the object f has been pushed to the DB, 
# and has been automatically assigned a unique primary key id

f.id
# is None

session.refresh(f)
# refresh updates given object in the session with its state in the DB
# (and can also only refresh certain attributes - search for documentation)

f.id
# is the automatically assigned primary key ID given in the database.

Nasıl yapılır bu.


8
Bu, benim için işe yarayabilecek bir yanıta yaklaşıyor, ancak aşağıdaki hatayı alıyorum: InvalidRequestError: '<....>' örneği yenilenemedi. Yıkamadan sonra örneğin artık mevcut olmadığı görülür. Herhangi bir bilgiyi takdir edin.
PlaidFan

1
Az önce kıçımı kurtardın. Django'dan gelen ORM'yi bir daha asla kullanacağımı sanmıyorum. Flush () komutu, belgelenen IMHO olarak ÇALIŞMAZ.
Marc

2
Güncelle, kullanmak zorunda kaldım sessionmaker(autoflush=True), bu combo w / renew () bana satır kimliğini sağladı. #grrr
Marc

5
Eğer arasındaki farkı anlamak daha dont Eğer flush()ve commit(), burada iyi bir açıklama verilmiştir: stackoverflow.com/a/4202016/1252290
EPOC

2
Yerine @PlaidFan flush()kullanımı commit()ve hemen ardından - ile yenileyin session.refresh(f), benim için çalışıyor ve ben SQLAlchemy sürümünü kullanın0.6.7
Ricky Levi

20

Herkese teşekkürler. Sorunumu sütun eşlemesini değiştirerek çözdüm. Benim autoincrement=Trueiçin gerekli.

Menşei:

id = Column('ID', Integer, primary_key=True, nullable=False)

değiştirildikten sonra:

id = Column('ID', Integer, primary_key=True, autoincrement=True, nullable=True)

sonra

session.flush()  
print(f.id)

tamam!


6

dpb tarafından verilen cevabın aksine, yenileme gerekli değildir. Bir kez yıkadığınızda, kimlik alanına erişebilirsiniz, sqlalchemy arka uçta otomatik olarak oluşturulan kimliği otomatik olarak yeniler

Bu problemle karşılaştım ve bazı araştırmalardan sonra kesin sebebini anladım, modelim tamsayı alanı olarak id ile oluşturuldu ve formumda id gizli alan ile temsil edildi (çünkü formumda kimliği göstermek istemedim). Gizli alan varsayılan olarak bir metin olarak temsil edilir. Widget = hiddenInput ()) ile formu integerfield olarak değiştirdiğimde sorun çözüldü.


1
Belirtildiği gibi sadece yenileme () benim için çalıştı. Veri geçişi yaparken, FK'yi doldurmak için bir döngüdeki satır kimliğine ihtiyacım vardı. İşe yarayan tek şey commit, flush, oturum hackleme ve yenileme () kombinasyonlarını denedim. Verilerim süper temiz ve sadece SQLA'nın gerçekten o kadar iyi olmadığını görüyorum (en az 5 ana ORMS'de önemli ölçüde deneyime sahip olmak). Bir add () -> commit () / flush () için satır kimliğini almaya çalışırken 5 saatten fazla sürüyor.
Marc

1

Bir keresinde yöntemi 0çağırmadan önce id'ye atanma konusunda bir sorun yaşadım session.add. Kimlik, veritabanı tarafından doğru bir şekilde atandı, ancak daha sonra oturumdan doğru kimlik alınmadı session.flush().


-7

Bunun session.save_or_update(f)yerine kullanmayı denemelisiniz session.add(f).


1
save_or_update0.5'ten beri kullanımdan kaldırıldı. session.add()yapmalı.
Pavel Repin
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.