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)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。