我有一个模型,我想包含一个主题名称及其首字母缩写(他的数据有些匿名并由首字母缩写跟踪)。
此刻,我写了
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'Mallory”首字母是“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 对此进行了介绍。
我不知道是否有更好的方法来做到这一点,但您可以为 the pre_save
signal use a signal handler:
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)
post_save
而不是 pre_save
。
**kwargs
参数?
使用 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
的值。
作为 Gabi Purcaru 答案的替代实现,您还可以使用 receiver
decorator 连接到 pre_save
信号:
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 采用。
不定期副业成功案例分享
super().save(*args, **kwargs)
(不带Subject, self
参数)。