Django nesnesini veritabanından yeniden yükle


161

Bir django nesnesinin durumunu veritabanından yenilemek mümkün mü? Demek istediğim davranış kabaca eşdeğer:

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

GÜNCELLEME: İzleyicide yeniden açma / alıştırma yapma savaşı bulundu: http://code.djangoproject.com/ticket/901 . Korucuların neden bu kadar hoşlanmadığını hala anlamıyorum.


Sıradan bir SQL bağlamında bu bir anlam ifade etmiyor. Veritabanı nesnesi ancak işleminiz bittikten ve değiştirildikten sonra değiştirilebilir commmit. Bunu yaptıktan sonra, bir sonraki SQL işleminin gerçekleşmesini beklemek zorunda kalacaksınız. Neden bunu yapıyorsun? Bir sonraki işlemi ne kadar bekleyeceksiniz?
S.Lott

Bu gereksiz bir işlev gibi görünüyor; nesneyi veritabanından yeniden aramak zaten mümkündür.
Stephan

Ben de bunu istiyorum, ama burada
eruciform

2
Bu uygun değildir çünkü Django model nesneleri proxy'lerdir. Aynı tablo satırını iki nesneye alırsanız - x1 = X.objects.get (id = 1); x2 = X.objects.get (id = 1), eşit olarak test ederler, ancak farklı nesnelerdir ve durum paylaşılmaz. Hem bağımsız olarak değiştirebilir hem de kaydedebilirsiniz - son kaydedilen, veritabanındaki satırın durumunu belirler. Bu nedenle basit atama ile yeniden yüklemek doğrudur - x1 = X.objects.get (id = 1). Yeniden yükleme yöntemine sahip olmak birçok insanın yanlış x1.f = 'yeni değer' anlamına gelmesini sağlar; (x1.f == x2.f) Doğru.
Paul Whipp

Yanıtlar:


260

Django 1.8'den itibaren yenilenen nesneler yerleşiktir. Dokümanlara bağlantı .

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 Evet, sadece 1.8'de uygulandı. Django'nun önceki sürümleri için en iyi diğer yanıtlardan biriyle devam edersiniz.
Tim Fletcher

1
Dokümanlar'da belirtilen "Ertelenmemiş alanların tümü güncellendi" nin ne anlama geldiğinden emin değil misiniz?
Yunti

1
@Yunti Alanları erteleyebilir veya açıkça yalnızca alanların bir alt kümesini isteyebilirsiniz ; sonuçta ortaya çıkan nesne yalnızca kısmen doldurulur. refresh_from_dbyalnızca önceden doldurulmuş bu tür alanları güncelleyecektir.
301_Moved_Permanently

Dokümanlardaki ayrıntılar bulunamadı, ancak DoesNotExistarama sırasında alttaki nesne silindiğinde düzgün bir istisna atar refresh_from_db. Bilginize.
Tim Tisdall

28

Ben nesne gibi veritabanından yeniden yüklemek nispeten kolay buldum :

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

19
Evet, ama ... bundan sonra bu nesneye yapılan tüm referansları güncellemelisiniz. Çok kullanışlı ve hataya açık değil.
grep

2
Kereviz django dışındaki db nesnemi güncellediğinde bu gerekli bulundu, django görünüşte değiştiğine dair hiçbir fikri olmadığı için nesnenin önbelleğini tuttu.
Bob Spryn

3
django.db.models.loading içe aktarım get_model; instance = get_model (örnek) .objects.get (pk = instance.pk)
Erik

1
@grep bu kullanım durumu için bir test yazarak 2 saat kaybetti: 1: Bir modeli başlatın; 2: Modeli bir Form aracılığıyla güncelleyin; 3: Yeni değerin güncellendiğini test edin .... Evet, hata eğilimli.
vlad-ardelean

3
Bence refresh_from_dbtüm bu sorunları çözer.
Flimm

16

@ Grep'in yorumuna istinaden, mümkün olmamalı:

# 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

Çözüm için teşekkürler. Sadece SO izin birden fazla oy!
user590028

11
Django artık refresh_from_dbyöntem sağlıyor.
17'de Flimm

9

@Flimm'in belirttiği gibi, bu gerçekten harika bir çözüm:

foo.refresh_from_db()

Bu, veritabanındaki tüm verileri nesneye yeniden yükler.

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.