Django模型字段默认基于在同一模型中的另一个字段

问题描述:

我有一个模型,我想包含主题名称和它们的首字母缩写。 (该数据在一定程度上匿名和缩写跟踪。)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’,并希望修复编辑它作为一个管理员)

模式肯定是有一个 “自我”!只是你试图将模型类的属性定义为依赖于模型实例;这是不可能的,因为实例在定义类及其属性之前没有(也不能)存在。

为了得到你想要的效果,覆盖模型类的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中。

我不知道是否有这样做的更好的办法,但可以use a signal handlerthe pre_save signal

​​
+1

您导入了```post_save```而不是```pre_save```。 – arkocal 2015-06-19 09:07:12

使用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的值。