Saya memiliki model yang saya ingin berisi nama subjek dan inisialnya (datanya agak dianonimkan dan dilacak dengan inisial).
Sekarang, saya menulis
class Subject(models.Model):
name = models.CharField("Name", max_length=30)
def subject_initials(self):
return ''.join(map(lambda x: '' if len(x)==0 else x[0],
self.name.split(' ')))
# Next line is what I want to do (or something equivalent), but doesn't work with
# NameError: name 'self' is not defined
subject_init = models.CharField("Subject Initials", max_length=5, default=self.subject_initials)
Seperti yang ditunjukkan oleh baris terakhir, saya lebih suka agar inisial benar-benar disimpan dalam database sebagai bidang (terlepas dari nama), tetapi itu diinisialisasi dengan nilai default berdasarkan bidang nama. Namun, saya mengalami masalah karena model django sepertinya tidak memiliki 'diri'.
Jika saya mengubah baris menjadi subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials)
, saya dapat melakukan syncdb, tetapi tidak dapat membuat subjek baru.
Apakah ini mungkin di Django, memiliki fungsi yang dapat dipanggil memberikan default untuk beberapa bidang berdasarkan nilai dari bidang lain?
(Bagi yang penasaran, alasan saya ingin memisahkan inisial toko saya secara terpisah adalah dalam kasus yang jarang terjadi di mana nama belakang yang aneh mungkin berbeda dari yang saya lacak. Misalnya, orang lain memutuskan bahwa Subjek 1 Bernama inisial "John O'Mallory" adalah "JM" bukan "JO" dan ingin memperbaiki mengeditnya sebagai administrator.)
sumber
super().save(*args, **kwargs)
(tanpaSubject, self
argumen) seperti pada contoh di dokumentasi yang direferensikan.Saya tidak tahu apakah ada cara yang lebih baik untuk melakukan hal ini, tetapi Anda dapat menggunakan penangan sinyal untuk para
pre_save
sinyal :from django.db.models.signals import pre_save def default_subject(sender, instance, using): if not instance.subject_init: instance.subject_init = instance.subject_initials() pre_save.connect(default_subject, sender=Subject)
sumber
post_save
bukanpre_save
.**kwargs
argumen yang harus dimiliki oleh semua fungsi receiver menurut docs.djangoproject.com/en/2.0/topics/signals/… ?save()
, mungkin diubah menjadi menimpa__init__
, lebih baik karena lebih eksplisit.Menggunakan sinyal Django , ini bisa dilakukan cukup dini, dengan menerima para
post_init
sinyal dari model.from django.db import models import django.dispatch class LoremIpsum(models.Model): name = models.CharField( "Name", max_length=30, ) subject_initials = models.CharField( "Subject Initials", max_length=5, ) @django.dispatch.receiver(models.signals.post_init, sender=LoremIpsum) def set_default_loremipsum_initials(sender, instance, *args, **kwargs): """ Set the default value for `subject_initials` on the `instance`. :param sender: The `LoremIpsum` class that sent the signal. :param instance: The `LoremIpsum` instance that is being initialised. :return: None. """ if not instance.subject_initials: instance.subject_initials = "".join(map( (lambda x: x[0] if x else ""), instance.name.split(" ")))
The
post_init
sinyal dikirim oleh kelas setelah telah dilakukan inisialisasi pada contoh. Dengan cara ini, instance mendapatkan nilainame
sebelum menguji apakah kolom non-nullable-nya telah disetel.sumber
save()
, mungkin diubah menjadi menimpa__init__
, lebih baik karena lebih eksplisit.Sebagai implementasi alternatif dari jawaban Gabi Purcaru , Anda juga dapat terhubung ke
pre_save
sinyal menggunakanreceiver
dekorator :from django.db.models.signals import pre_save from django.dispatch import receiver @receiver(pre_save, sender=Subject) def default_subject(sender, instance, **kwargs): if not instance.subject_init: instance.subject_init = instance.subject_initials()
Fungsi penerima ini juga mengambil
**kwargs
argumen kata kunci wildcard yang harus diambil oleh semua penangan sinyal sesuai dengan https://docs.djangoproject.com/en/2.0/topics/signals/#receiver-functions .sumber