โหลดวัตถุ django จากฐานข้อมูล


160

เป็นไปได้หรือไม่ที่จะรีเฟรชสถานะของวัตถุ django จากฐานข้อมูล? ฉันหมายถึงพฤติกรรมที่เทียบเท่ากับ:

new_self = self.__class__.objects.get(pk=self.pk)
for each field of the record:
    setattr(self, field, getattr(new_self, field))

UPDATE:พบเปิด / สงคราม wontfix ในการติดตาม: http://code.djangoproject.com/ticket/901 ยังไม่เข้าใจว่าทำไมผู้ดูแลไม่ชอบสิ่งนี้


ในบริบท SQL ธรรมดาสิ่งนี้ไม่สมเหตุสมผล วัตถุฐานข้อมูลเท่านั้นที่สามารถเปลี่ยนแปลงได้หลังจากcommmitเสร็จสิ้นการทำธุรกรรมของคุณและไม่ได้ เมื่อคุณทำเช่นนั้นแล้วคุณจะต้องรอให้ธุรกรรม SQL ถัดไปรอ ทำไมทำอย่างนั้น? นานแค่ไหนที่คุณจะรอการทำธุรกรรมต่อไป?
S.Lott

ดูเหมือนว่าฟังก์ชั่นที่ไม่มีความจำเป็น เป็นไปได้อยู่แล้วที่จะค้นหาวัตถุจากฐานข้อมูลอีกครั้ง
เตฟาน

ฉันต้องการสิ่งนี้เช่นกัน แต่มันถูกปิดซ้ำแล้วซ้ำอีกที่นี่
eruciform

2
ไม่เหมาะสมเนื่องจากวัตถุต้นแบบของ Django เป็นพร็อกซี หากคุณได้รับแถวตารางเดียวกันเป็นสองวัตถุ - x1 = X.objects.get (id = 1) x2 = X.objects.get (id = 1) พวกเขาจะทดสอบเท่ากัน แต่เป็นวัตถุที่แตกต่างกันและสถานะจะไม่ถูกแชร์ คุณสามารถเปลี่ยนได้ทั้งอิสระและบันทึก - บันทึกล่าสุดกำหนดสถานะของแถวในฐานข้อมูล ดังนั้นจึงถูกต้องในการโหลดซ้ำด้วยการมอบหมายอย่างง่าย - x1 = X.objects.get (id = 1) การมีวิธีการโหลดซ้ำจะทำให้หลายคนสรุปผิดว่า x1.f = 'ค่าใหม่'; (x1.f == x2.f) เป็นจริง
Paul Whipp

คำตอบ:


259

ในฐานะของ Django 1.8 วัตถุสดชื่นถูกสร้างขึ้นใน. เชื่อมโยงไปยังเอกสาร

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

@ fcracker79 ใช่มันมีการใช้งานใน 1.8 เท่านั้น สำหรับรุ่นก่อนหน้าของ Django คุณควรไปด้วยคำตอบอย่างใดอย่างหนึ่งที่ดีที่สุด
ทิมเฟลตเชอร์

1
ไม่แน่ใจว่ามีการอัปเดต "ฟิลด์ที่ไม่มีการเลื่อนเวลาทั้งหมด" ที่กล่าวถึงในเอกสารหรือไม่
Yunti

1
@Yunti คุณสามารถเลื่อนฟิลด์ได้หรือขอเฉพาะส่วนย่อยของฟิลด์อย่างชัดเจนและวัตถุที่เป็นผลลัพธ์จะมีเพียงบางส่วนเท่านั้น refresh_from_dbจะอัปเดตฟิลด์ที่มีประชากรอยู่แล้วเท่านั้น
301_Moved_Permanently

ไม่สามารถหารายละเอียดในเอกสาร แต่มันถูกพ่นยกเว้นถ้าวัตถุต้นแบบถูกลบเมื่อโทรDoesNotExist refresh_from_dbFYI
Tim Tisdall

28

ฉันพบว่ามันค่อนข้างง่ายในการโหลดวัตถุจากฐานข้อมูลเช่น:

x = X.objects.get(id=x.id)

19
ใช่ แต่ ... หลังจากนั้นคุณต้องอัปเดตการอ้างอิงทั้งหมดไปยังวัตถุนี้ ไม่สะดวกและผิดพลาดได้ง่าย
grep

2
พบสิ่งนี้มีความจำเป็นเมื่อ Celery อัปเดตวัตถุของฉันใน db นอก django, django ดูเหมือนจะเก็บแคชของวัตถุไว้เพราะมันไม่รู้ว่ามันเปลี่ยนไป
Bob Spryn

3
จาก django.db.models.loading นำเข้า get_model; อินสแตนซ์ = get_model (อินสแตนซ์) .objects.get (pk = instance.pk)
Erik

1
@grep หายไปเพียง 2 ชั่วโมงในการเขียนแบบทดสอบสำหรับกรณีการใช้งานนี้: 1: เริ่มต้นโมเดล; 2: อัปเดตโมเดลผ่านแบบฟอร์ม; 3: ทดสอบว่ามีการอัปเดตค่าใหม่ใช่แล้วมีข้อผิดพลาดเกิดขึ้นได้ง่าย
vlad-ardelean

3
ฉันคิดว่าrefresh_from_dbแก้ปัญหาทั้งหมดเหล่านี้
Flimm

16

จากการอ้างอิงถึงความคิดเห็นของ @ grep ไม่ควรทำ:

# Put this on your base model (or monkey patch it onto django's Model if that's your thing)
def reload(self):
    new_self = self.__class__.objects.get(pk=self.pk)
    # You may want to clear out the old dict first or perform a selective merge
    self.__dict__.update(new_self.__dict__)

# Use it like this
bar.foo = foo
assert bar.foo.pk is None
foo.save()
foo.reload()
assert bar.foo is foo and bar.foo.pk is not None

ขอบคุณสำหรับการแก้ปัญหา ถ้าเป็นเช่นนั้นอนุญาตให้มีการโหวตหลายครั้งเท่านั้น!
user590028

11
Django ตอนนี้ให้refresh_from_dbวิธีการ
Flimm

9

ตามที่ @Flimm ชี้ให้เห็นว่านี่เป็นทางออกที่ยอดเยี่ยมจริงๆ:

foo.refresh_from_db()

นี่จะโหลดข้อมูลทั้งหมดจากฐานข้อมูลไปยังวัตถุ

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