1. ホーム
  2. python

[解決済み] Django モデルフィールドのデフォルトは、同じモデル内の別のフィールドに基づく

2022-09-26 03:47:02

質問

被験者の名前とイニシャルを含むモデルがあります(データは多少匿名化され、イニシャルで追跡されます)。

今、私は

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 のモデルには 'self' がないようなので、問題があります。

この行を subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials) に変更すると、syncdbはできますが、新しいsubjectを作成することができません。

Django で、呼び出し可能な関数が他のフィールドの値に基づいてあるフィールドにデフォルトを与えるということは可能でしょうか?

(不思議なことに、私がストアのイニシャルを別々に分けたい理由は、稀なケースとして、奇妙な姓が私が追跡しているものと異なる場合があるからです。 たとえば、他の誰かが Subject 1 Named "John O'Mallory" のイニシャルが "JO" ではなく "JM" であると判断し、管理者としてそれを修正編集したいと考えています)。

どのように解決するのですか?

モデルには確かに "self" があります! モデル クラスの属性をモデル インスタンスに依存するものとして定義しようとしているだけです。クラスとその属性を定義する前にインスタンスが存在しない (存在しえない) ので、それは不可能です。

望む効果を得るために、モデルクラスのsave()メソッドをオーバーライドします。 インスタンスに必要な変更を加えてから、スーパークラスのメソッドを呼び出して実際の保存を行います。 以下は簡単な例です。

def save(self, *args, **kwargs):
    if not self.subject_init:
        self.subject_init = self.subject_initials()
    super(Subject, self).save(*args, **kwargs)

これは モデルメソッドのオーバーライド で説明されています。