サブジェクト名とそのイニシャルを含めたいモデルがあります。 (データは多少匿名化され、イニシャルによって追跡されます。)
今、私は書いた
_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)
_
最後の行で示されているように、イニシャルを実際にはデータベースにフィールドとして(名前とは無関係に)保存することができますが、名前フィールドに基づくデフォルト値で初期化されます。ただし、Djangoモデルには「自己」がないようです。
行をsubject_init = models.CharField("Subject initials", max_length=2, default=subject_initials)
に変更すると、syncdbは実行できますが、新しいサブジェクトを作成できません。
これはDjangoで可能ですか?呼び出し可能な関数が別のフィールドの値に基づいていくつかのフィールドにデフォルトを与えますか?
(好奇心のために、ストアのイニシャルを別々にしたい理由は、奇妙な姓が追跡しているものと異なる場合がまれにあることです。例えば、他の誰かが「John O'Mallory」という名前のイニシャルを「JO」ではなく「JM」で、管理者として編集を修正したい。)
モデルには確かに「自己」があります!モデルクラスの属性をモデルインスタンスに依存していると定義しようとしているだけです。クラスとその属性を定義する前にインスタンスが存在しない(そして存在できない)ため、それは不可能です。
目的の効果を得るには、モデルクラスのsave()メソッドをオーバーライドします。インスタンスに必要な変更を加えてから、スーパークラスのメソッドを呼び出して実際の保存を行います。以下に簡単な例を示します。
def save(self, *args, **kwargs):
if not self.subject_init:
self.subject_init = self.subject_initials()
super(Subject, self).save(*args, **kwargs)
これは、ドキュメントの モデルメソッドのオーバーライド で説明されています。
これを行うより良い方法があるかどうかはわかりませんが、 シグナルハンドラを使用する for the pre_save
signal :
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)
Djangoシグナル を使用すると、モデルから _post_init
_シグナル を受信することで、これをかなり早く行うことができます。
_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(" ")))
_
_post_init
_シグナルは、インスタンスで初期化が完了するとクラスによって送信されます。このようにして、インスタンスは、null不可フィールドが設定されているかどうかをテストする前に、name
の値を取得します。
Gabi Purcar の答えの代替実装として、pre_save
receiver
デコレーターを使用したシグナル :
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()
このレシーバー関数は、**kwargs
すべてのシグナルハンドラが https://docs.djangoproject.com/en/2.0/topics/signals/#receiver-functions に従って取得する必要があるワイルドカードキーワード引数。