sqlalchemy flush () และรับ id แทรก?


114

ฉันต้องการทำสิ่งนี้:

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

แต่f.idคือNoneเมื่อลองแล้ว. ฉันจะทำงานนี้ได้อย่างไร


2
คุณสามารถเริ่มต้น SA engine ด้วยecho=Trueและดูว่า SQL ใดถูกเรียกใช้งานในช่วงเวลาฟลัช - ไทม์? สิ่งที่คุณอธิบายควรใช้งานได้และให้รหัสแก่คุณ แต่อาจมีปัญหาอื่น ๆ ที่ส่งผลให้ f.id เป็น None
Pavel Repin

คำตอบ:


63

โค้ดตัวอย่างของคุณควรใช้งานได้ตามที่เป็นอยู่ SQLAlchemy ควรให้ค่าf.idโดยสมมติว่าเป็นคอลัมน์คีย์หลักที่สร้างอัตโนมัติ แอตทริบิวต์คีย์หลักจะถูกเติมทันทีภายในflush()กระบวนการเมื่อสร้างขึ้นและไม่commit()จำเป็นต้องเรียกใช้ ดังนั้นคำตอบจึงอยู่ในข้อใดข้อหนึ่งต่อไปนี้:

  1. รายละเอียดของการทำแผนที่ของคุณ
  2. หากมีการใช้งานแบ็กเอนด์แปลก ๆ (เช่น SQLite จะไม่สร้างค่าจำนวนเต็มสำหรับคีย์หลักแบบผสม)
  3. สิ่งที่ SQL ที่ปล่อยออกมาพูดเมื่อคุณเปิดเสียงสะท้อน

1
คุณถูกต้องการตรวจสอบอย่างรวดเร็วในเชลล์แสดงให้เห็นว่ามีการเติมฟิลด์คีย์หลักด้วยค่า ฉันจะต้องตรวจสอบว่าเหตุใดจึงไม่ได้ผลในทางปฏิบัติ
Eloff

3
"โค้ดตัวอย่างของคุณควรให้ค่า" ดูเหมือนคุณกำลังพูดว่า "คุณควรกำหนดค่าสำหรับ id ตั้งแต่แรก" แทนที่จะเป็น "โค้ดที่คุณควรจะใช้งานได้ตามที่เป็นอยู่" เห็นได้ชัดว่าคุณหมายถึงสิ่งหลังมากกว่าการอ่านครั้งที่สามเท่านั้น คุณช่วยชี้แจงได้ไหม
สุ่ม

127

ฉันเพิ่งเจอปัญหาเดียวกันและหลังจากการทดสอบฉันพบว่าไม่มีคำตอบเหล่านี้เพียงพอ

ในปัจจุบันหรือในขณะที่ sqlalchemy .6+ มีวิธีแก้ปัญหาที่ง่ายมาก (ฉันไม่รู้ว่ามีอยู่ในเวอร์ชันก่อนหน้าหรือไม่ แต่ฉันคิดว่าเป็นเช่นนั้น):

session.refresh ()

ดังนั้นรหัสของคุณจะมีลักษณะดังนี้:

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.

นั่นคือวิธีการทำ


8
นี่กำลังเข้าใกล้คำตอบที่อาจใช้ได้ผลสำหรับฉัน แต่ฉันได้รับข้อผิดพลาดต่อไปนี้: InvalidRequestError: ไม่สามารถรีเฟรชอินสแตนซ์ '<.... >' ปรากฏขึ้นหลังจากการล้างข้อมูลว่าอินสแตนซ์นั้นไม่มีอยู่อีกต่อไป ชื่นชมข้อมูลเชิงลึก
PlaidFan

1
คุณเพิ่งช่วยลาของฉัน ฉันไม่คิดว่าจะใช้ ORM ที่มาจาก Django อีกแล้ว คำสั่ง flush () ไม่ทำงานเป็นเอกสาร IMHO
Marc

2
อัปเดตฉันต้องใช้sessionmaker(autoflush=True)คำสั่งผสมที่ w / refresh () ให้ ID แถวแก่ฉัน #grrr
Marc

5
หากคุณไม่เข้าใจความแตกต่างระหว่างflush()และcommit()นี่คือคำอธิบายที่ดี: stackoverflow.com/a/4202016/1252290
Epoc

2
@PlaidFan แทนที่จะflush()ใช้งานcommit()และหลังจากนั้น - รีเฟรชด้วยใช้session.refresh(f)งานได้สำหรับฉันและฉันใช้เวอร์ชัน SQLAlchemy0.6.7
Ricky Levi

20

ขอบคุณสำหรับทุกคน ฉันแก้ไขปัญหาของฉันโดยแก้ไขการแมปคอลัมน์ สำหรับฉันautoincrement=Trueจำเป็นต้องมี

ที่มา:

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

หลังจากแก้ไข:

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

แล้ว

session.flush()  
print(f.id)

โอเค!


6

ไม่เหมือนกับคำตอบที่ได้รับจาก dpb การรีเฟรชไม่จำเป็น เมื่อคุณล้างคุณสามารถเข้าถึงฟิลด์ id ได้ sqlalchemy จะรีเฟรช id โดยอัตโนมัติซึ่งสร้างขึ้นโดยอัตโนมัติที่แบ็กเอนด์

ฉันพบปัญหานี้และหาสาเหตุที่แท้จริงหลังจากการตรวจสอบบางอย่างโมเดลของฉันถูกสร้างขึ้นโดยมี id เป็นจำนวนเต็มและในรูปแบบของฉัน id ถูกแสดงด้วย hiddenfield (เนื่องจากฉันไม่ต้องการแสดง id ในแบบฟอร์มของฉัน) ฟิลด์ที่ซ่อนอยู่โดยค่าเริ่มต้นจะแสดงเป็นข้อความ เมื่อฉันเปลี่ยนฟอร์มเป็น integerfield ด้วย widget = hiddenInput ()) ปัญหาได้รับการแก้ไข


1
ตามที่ระบุไว้เท่านั้น refresh () ใช้ได้ผลสำหรับฉัน ในการย้ายข้อมูลฉันต้องการ ID แถวในลูปเพื่อเติมข้อมูล FK ฉันลองทุกคอมโบของคอมโบล้างเซสชันแฮ็คและรีเฟรช () เป็นสิ่งเดียวที่ใช้ได้ผล ข้อมูลของฉันสะอาดมากและฉันเพิ่งพบว่า SQLA ไม่ค่อยดีเท่าไหร่ (มี exp มากใน ORMS หลักอย่างน้อย 5 รายการ) เพียงแค่ห่อเป็นเวลา 5+ ชั่วโมงพยายามรับรหัสแถวสำหรับการเพิ่ม () -> กระทำ () / ฟลัช ()
Marc

1

ฉันเคยมีปัญหากับการกำหนดให้0กับ id ก่อนsession.addวิธีการโทร ID ถูกกำหนดอย่างถูกต้องโดยฐานข้อมูล แต่ id ที่ถูกต้องไม่ได้รับจากเซสชันหลังจากsession.flush()นั้น


-7

คุณควรลองใช้session.save_or_update(f)แทนsession.add(f).


1
save_or_updateเลิกใช้งานตั้งแต่ 0.5 หรือมากกว่านั้น session.add()ควรทำ
Pavel Repin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.