post_save di Django untuk segera memperbarui instance

Saya mencoba untuk segera memperbarui catatan setelah disimpan. Contoh ini mungkin tampak tidak berguna, tetapi bayangkan kita perlu menggunakan API setelah data disimpan untuk mendapatkan info tambahan dan memperbarui catatan:

def my_handler(sender, instance=False, **kwargs):
    t = Test.objects.filter(id=instance.id)
    t.blah = 'hello'
    t.save()

class Test(models.Model):
    title = models.CharField('title', max_length=200)
    blah = models.CharField('blah', max_length=200)

post_save.connect(my_handler, sender=Test)

Jadi kolom 'ekstra' seharusnya disetel ke 'halo' setelah setiap penyimpanan. Benar? Tapi itu tidak berhasil.

Ada ide?


person givp    schedule 28.10.2009    source sumber
comment
Mungkin Anda bisa menjelaskan bagaimana itu tidak berfungsi? Pada awalnya, sepertinya itu akan membuat loop tak terbatas, karena post_save memanggil save, yang seharusnya memanggil post_save, dll. Mungkin Django mencegah rekursi?   -  person Ned Batchelder    schedule 29.10.2009
comment
Saya melihat lingkaran tak terbatas di sana. Setelah t.save() sinyal post_save dikirim, tebak fungsi mana yang dipanggil...   -  person stefanw    schedule 29.10.2009
comment
oh, saya mendapat kesan Django tidak akan membiarkan simpanan kedua memicu post_save lagi? Saya rasa tidak. Dalam hal ini, Anda benar. Ini akan menjadi putaran yang tak terbatas. Tapi saya tidak melihat loop atau apa pun.   -  person givp    schedule 29.10.2009
comment
Ini mungkin pertanyaan bodoh, tetapi tidak bisakah Anda melakukan panggilan API terlebih dahulu lalu menyimpannya?   -  person Matt Baker    schedule 29.10.2009
comment
maksudmu menggunakan pre_save? Saya harus melakukannya di tingkat model karena saya tidak dapat memodifikasi admin Django dengan cara apa pun untuk proyek ini.   -  person givp    schedule 29.10.2009
comment
Mengapa Anda tidak memperbarui metode save saja menjadi ; self.blah= 'hello'; super( Test, self ).save( *args, **kw )? Apa yang salah dengan mengganti save()?   -  person S.Lott    schedule 29.10.2009
comment
Jika Anda mengubah kode ulang .update() alih-alih save(). Untuk menghindari perulangan. Karena update() tidak memanggil sinyal post_save.   -  person Brandon Bertelsen    schedule 26.02.2013


Jawaban (2)


Saat Anda menggunakan sinyal post_save untuk memperbarui objek kelas pengirim, kemungkinan besar Anda harus mengganti metode simpan. Dalam kasus Anda, definisi model akan terlihat seperti:

class Test(models.Model):
    title = models.CharField('title', max_length=200)
    blah = models.CharField('blah', max_length=200)

    def save(self, force_insert=False, force_update=False):
        if not self.blah:
            self.blah = 'hello'
        super(Test, self).save(force_insert, force_update)
person ozan    schedule 29.10.2009
comment
Jika dia melakukan ini pada model admin, post_save adalah solusi yang lebih baik daripada membuat subkelas model admin yang ada dan mengesampingkan penyimpanan. - person Paul McMillan; 29.10.2009
comment
using=False diperlukan pada daftar argumen metode 'simpan' di Django 1.3 dan lebih tinggi - person eviltnan; 20.07.2012
comment
Mengganti metode penyimpanan tidak selalu cocok karena kita tidak memiliki kunci utama sampai kita memanggil simpan. Jadi jika Anda perlu bekerja dengan PK suatu instance, satu-satunya pilihan adalah post_save - person chhantyal; 27.03.2015
comment
Cara masa depan untuk mengganti metode save sambil menyertakan semua argumen yang diperlukan adalah: def save(self, *args, **kwargs): - person yndolok; 21.04.2015

Bukankah pengendali post_save mengambil contoh? Mengapa Anda memfilter menggunakannya? Mengapa tidak melakukan saja:

def my_handler(sender, instance=False, created, **kwargs):
  if created:
     instance.blah = 'hello'
     instance.save()

Kode Anda yang ada tidak berfungsi karena berulang, dan Test.objects.filter(id=instance.id) mengembalikan kumpulan kueri, bukan objek. Untuk mendapatkan satu objek secara langsung, gunakan Queryset.get(). Namun Anda tidak perlu melakukan itu di sini. Argumen yang dibuat menjaganya agar tidak berulang, karena hanya disetel pertama kali.

Secara umum, kecuali Anda benar-benar perlu menggunakan sinyal post_save, Anda tetap harus mengganti metode save() objek Anda.

person Paul McMillan    schedule 28.10.2009
comment
Saya sebenarnya mencobanya juga tidak berhasil. tetapi jika orang-orang di atas benar, saya tetap tidak dapat melakukan ini karena hanya akan terjebak dalam loop post_save. - person givp; 29.10.2009
comment
Cobalah menggunakan bendera yang dibuat. Saya pikir itu akan memperbaiki masalah Anda, karena dibuat tidak disetel pada loop berikutnya. - person Paul McMillan; 29.10.2009
comment
Anda mungkin ingin melihat pertanyaan ini untuk info lebih lanjut tentang kapan menggunakan sinyal dan kapan harus mengganti penyimpanan: stackoverflow.com/questions/170337/ - person Paul McMillan; 29.10.2009
comment
ya! Saya memiliki nilai kebenaran pengujian untuk bendera yang dibuat yang sedikit salah. Ini seharusnya berfungsi sekarang... - person Paul McMillan; 29.10.2009
comment
Poster aslinya tidak menyebutkan dia ingin handler dipanggil hanya ketika rekor baru dibuat. Jadi, menggunakan tanda 'dibuat' tidak menyelesaikan masalah, jika penangan harus dipanggil juga saat pembaruan. (Saya sendiri mencoba mencari solusi untuk masalah serupa.) - person jholster; 22.11.2010
comment
jholster: Kemudian picu setiap kali dijalankan, abaikan argumen created. - person Paul McMillan; 23.11.2010