2010-12-07 85 views
55

我有一個模型,我想包含主題名稱和它們的首字母縮寫。 (該數據在一定程度上匿名和縮寫跟蹤。)Django模型字段默認基於在同一模型中的另一個字段

現在,我寫

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,具有可調用的函數給出了基於另一個字段的值默認爲一些領域? (好奇的是,我想分開分開我店鋪名字的原因很罕見,奇怪的姓氏可能與我追蹤的姓氏不同,例如,其他人認爲主題1命名爲「John O」馬洛裏」的縮寫是‘JM’,而不是‘JO’,並希望修復編輯它作爲一個管理員)

回答

53

模式肯定是有一個 「自我」!只是你試圖將模型類的屬性定義爲依賴於模型實例;這是不可能的,因爲實例在定義類及其屬性之前沒有(也不能)存在。

爲了得到你想要的效果,覆蓋模型類的save()方法。對所需的實例進行任何更改,然後調用超類的方法來執行實際的保存。這是一個簡單的例子。

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

這在文檔中涵蓋在Overriding Model Methods中。

0

使用Django signals,這可以很早就完成,從模型接受的the post_init signal

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信號由類一旦完成初始化的實例發送。這樣,實例在測試是否設置了非空字段之前獲取name的值。

相關問題