我有
Model
:
class Question(models.Model):
type = models.CharField(
choices=[["text", "Text"], ["choice", "Choice"]],
max_length=6,
)
structure = models.JSONField(
default=dict,
)
def get_default_structure(self) -> dict:
if self.type == "text":
return {"maxLength": None}
if self.type == "choice":
return {"variants": []}
return dict()
@receiver(post_init, sender=Question)
def set_default_structure(sender: Type[Question], **kwargs):
instance = kwargs["instance"]
if not instance.structure:
instance.structure = instance.get_default_structure()
还有
Form
和ModelAdmin
:
class QuestionForm(ModelForm):
class Meta:
model = Question
fields = "__all__"
@admin.register(Question)
class QuestionAdmin(admin.ModelAdmin):
form = QuestionForm
按照逻辑,初始化一个空的
Question
后,structure
字段应该被覆盖,而且确实如此。
但出于某种原因,管理表单仍然显示从 {}
获得的 default=dict
值。
为什么会发生这种情况以及如何使 structure
小部件显示的不是 {}
值,而是从 get_default_structure
方法获取的值?
创建表单并与实例链接后,它不会自动检测对该实例所做的后续更改。因此,当您使用
post_init
信号更新结构时,表单不会“看到”此更改。也许显式设置表单的初始数据以匹配模型实例的当前状态,可以修复它。
为此,您可以重写表单的
__init__
方法,以根据实例的类型更新结构字段的初始值。
class QuestionForm(ModelForm):
...
def __init__(self, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
if self.instance and not self.instance.structure:
self.initial['structure'] = self.instance.get_default_structure()