Django 管理员:JSONField 默认空字典不会保存在管理员中
Django Admin: JSONField default empty dict wont save in admin
在我的模型定义中我有
from django.contrib.postgres.fields import JSONField
.....
.......
.........
media_data=JSONField(default=dict)
我创建了默认管理员
当我尝试在不触及该字段的情况下进行保存时,出现 this field is required
错误。
这看起来像是一个表单验证问题,因为我可以通过编程方式从代码中保存模型实例而不会出现问题。
为什么会这样?
我错过了什么傻事吗?
根据您的要求,考虑使用空白 and/or null。
media_data=JSONField(blank=True, null=True)
这最近给我带来了问题,尽管使用 django-mysql
而不是 postgres,并且是在自定义 ModelForm
而不是管理界面中。
我最终覆盖了模型的 save()
方法:
from django_mysql.models import JSONField
class yourModel(model):
media_data=JSONField(default=dict, blank=True)
def clean(self, *args, **kwargs):
if self.media_data is None:
self.media_data = "{}"
def save(self, *args, **kwargs):
self.clean()
super().save(*args, **kwargs)
- 发生了什么事。
当深入研究源代码时。我们可以看到以下调用堆栈:
1) form.is_valid()
->form.full_clean()
-->form._clean_fields()
---> self.cleand_data[name] = field.clean(value)
2) field.clean(value)
-> self.to_python(value)
-> self.validate(value)
查看源码可以发现,主要是因为empty_values
校验
# These values, if given to validate(), will trigger the self.required check.
EMPTY_VALUES = (None, '', [], (), {})
如您所见,空字典 {}
是 JSONField 的空值。所以它会引发错误。
- 我们能做什么?
解决方案是自定义 models.JSONField 和 forms.JSONField,如下所示。
forms.py
from django.contrib.postgres import forms
class MyJSONField(forms.JSONField):
empty_values = [None, "", [], ()]
db/fields.py
class MyJSONField(JSONField):
def formfield(self, **kwargs):
from ..forms import MyJSONField
return super().formfield(**{"form_class": MyJSONField, **kwargs})
我以前也遇到过类似的问题。在您的表单字段中添加 required=False
将解决问题。
class YourForm(forms.ModelForm):
media_data = SimpleArrayField(JSONField(), required=False, widget=forms.Textarea, delimiter='|')
我遇到了同样的问题。我是怎么修好的?为了绕过将 {}
排除为有效 json 的验证过程,我添加了 blank=True
和 null=True
。例如:models.JSONField(blank=True, null=True, default=dict)
我遇到了同样的问题,同样我创建了一个新的基于字段的 class 但我没有使用表单和模型字段,而是做了一个在实例化后调整表单字段内部结构的字段。
class CustomJSONField(JSONField):
empty_values = [None, '', [], ()]
def formfield(self, **kwargs):
result = super().formfield(**kwargs)
result.empty_values = self.empty_values
return result
在我的模型定义中我有
from django.contrib.postgres.fields import JSONField
.....
.......
.........
media_data=JSONField(default=dict)
我创建了默认管理员
当我尝试在不触及该字段的情况下进行保存时,出现 this field is required
错误。
这看起来像是一个表单验证问题,因为我可以通过编程方式从代码中保存模型实例而不会出现问题。
为什么会这样?
我错过了什么傻事吗?
根据您的要求,考虑使用空白 and/or null。
media_data=JSONField(blank=True, null=True)
这最近给我带来了问题,尽管使用 django-mysql
而不是 postgres,并且是在自定义 ModelForm
而不是管理界面中。
我最终覆盖了模型的 save()
方法:
from django_mysql.models import JSONField
class yourModel(model):
media_data=JSONField(default=dict, blank=True)
def clean(self, *args, **kwargs):
if self.media_data is None:
self.media_data = "{}"
def save(self, *args, **kwargs):
self.clean()
super().save(*args, **kwargs)
- 发生了什么事。 当深入研究源代码时。我们可以看到以下调用堆栈:
1) form.is_valid()
->form.full_clean()
-->form._clean_fields()
---> self.cleand_data[name] = field.clean(value)
2) field.clean(value)
-> self.to_python(value)
-> self.validate(value)
查看源码可以发现,主要是因为empty_values
校验
# These values, if given to validate(), will trigger the self.required check.
EMPTY_VALUES = (None, '', [], (), {})
如您所见,空字典 {}
是 JSONField 的空值。所以它会引发错误。
- 我们能做什么? 解决方案是自定义 models.JSONField 和 forms.JSONField,如下所示。
forms.py
from django.contrib.postgres import forms
class MyJSONField(forms.JSONField):
empty_values = [None, "", [], ()]
db/fields.py
class MyJSONField(JSONField):
def formfield(self, **kwargs):
from ..forms import MyJSONField
return super().formfield(**{"form_class": MyJSONField, **kwargs})
我以前也遇到过类似的问题。在您的表单字段中添加 required=False
将解决问题。
class YourForm(forms.ModelForm):
media_data = SimpleArrayField(JSONField(), required=False, widget=forms.Textarea, delimiter='|')
我遇到了同样的问题。我是怎么修好的?为了绕过将 {}
排除为有效 json 的验证过程,我添加了 blank=True
和 null=True
。例如:models.JSONField(blank=True, null=True, default=dict)
我遇到了同样的问题,同样我创建了一个新的基于字段的 class 但我没有使用表单和模型字段,而是做了一个在实例化后调整表单字段内部结构的字段。
class CustomJSONField(JSONField):
empty_values = [None, '', [], ()]
def formfield(self, **kwargs):
result = super().formfield(**kwargs)
result.empty_values = self.empty_values
return result