Django自定义YamlField实现过程解析
需求
在使用djangoadmin时希望后台的Textarea多行文本框可以按yaml格式编写,数据库保存为Text文本类型,字段和接口中读取出来自动变为字典或列表格式。
试过pipinstalldjango-yamlfied,修改支持新版django之后
接口中返回的字段是字符串形式,不符合预期。
之前写过一版。
importyaml
fromdjango.dbimportmodels
classYamlField(models.TextField):
defto_python(self,value):#将数据库内容转为python对象时调用
ifnotvalue:
value={}
ifisinstance(value,(list,dict)):
returnvalue
returnyaml.safe_load(value)
defget_prep_value(self,value):#create时插入数据,转为字符串存储
returnvalueifvalueisNoneelseyaml.dump(value,default_flow_style=False)
deffrom_db_value(self,value,expression,connection):#从数据库读取字段是调用
returnself.to_python(value)
问题是输入框输入
-a
-b
-c
保存后就会变成字典的字符串形式
['a','b','c']
无法原样保存,反复研究后,参考django-jsonfield写了一版。
原理是,改为继承models.Field类,(继承models.TextField类,则formfield和value_to_string不生效)
数据库依旧将数据库中的yaml文本转为dict/list,在djangoadmin中通过自定义widget显示为yaml字符串格式。
为了保存时,验证表单中yaml字符串格式是否正确,还需要自定义一个form。完整代码如下。
importdjango
fromdjango.dbimportmodels
fromdjangoimportforms
fromdjango.core.exceptionsimportValidationError
importyaml
classYamlWidget(forms.Textarea):
defrender(self,name,value,attrs=None,renderer=None):
ifvalueisNone:
value=""
ifnotisinstance(value,str):
value=yaml.safe_dump(value,default_flow_style=False)
ifdjango.VERSION<(2,0):
returnsuper().render(name,value,attrs)
returnsuper().render(name,value,attrs,renderer)
classYamlFormField(forms.CharField):
empty_values=[None,'']
def__init__(self,*args,**kwargs):
if'widget'notinkwargs:
kwargs['widget']=YamlWidget
super().__init__(*args,**kwargs)
defto_python(self,value):
ifisinstance(value,str)andvalue:
try:
returnyaml.safe_load(value)
exceptExceptionasexc:
raiseforms.ValidationError('Yamldecodeerror:%s'%(exc.args[0],))
else:
returnvalue
defvalidate(self,value):
ifvalueinself.empty_valuesandself.required:
raiseforms.ValidationError(self.error_messages['required'],code='required')
classYamlField(models.Field):
description="Yamlobject"
defget_internal_type(self):
return'TextField'
defformfield(self,**kwargs):
defaults={
'form_class':YamlFormField,
'widget':YamlWidget
}
defaults.update(**kwargs)
returnsuper().formfield(**defaults)
defto_python(self,value:str):#将数据库内容转为python对象时调用
ifvalueisNone:
ifnotself.nullandself.blank:
return""
returnNone
ifisinstance(value,(list,dict)):
returnvalue
value=yaml.safe_load(value)
returnvalue
defvalidate(self,value,model_instance):#验证从接受到字典格式
ifnotself.nullandvalueisNone:
raiseValidationError(self.error_messages['null'])
try:
self.get_prep_value(value)
exceptValueError:
raiseValidationError(self.error_messages['invalid']%value)
defget_prep_value(self,value:(list,dict)):#保存时插入数据,转为字符串存储
ifvalueisNone:
returnNone
value=yaml.safe_dump(value,default_flow_style=False)
returnvalue
deffrom_db_value(self,value:str,expression,connection,*args,**kwargs):#从数据库读取字段是调用
returnself.to_python(value)
defvalue_to_string(self,obj):#RestFramework调用时
returnself.value_from_object(obj)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。