需求
在使用django admin时希望后台的Textarea多行文本框可以按yaml格式编写,数据库保存为Text文本类型,字段和接口中读取出来自动变为字典或列表格式。
试过pip install django-yamlfied,修改支持新版django之后
接口中返回的字段是字符串形式,不符合预期。
之前写过一版。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | import yaml from django.db import models class YamlField(models.TextField): def to_python( self , value): # 将数据库内容转为python对象时调用 if not value: value = {} if isinstance(value, (list, dict)): return value return yaml.safe_load(value) def get_prep_value( self , value): # create时插入数据, 转为字符串存储 return value if value is None else yaml.dump(value, default_flow_style = False ) def from_db_value( self , value, expression, connection): # 从数据库读取字段是调用 return self .to_python(value) |
问题是输入框输入
- a
- b
- c
保存后就会变成字典的字符串形式
['a','b','c']
无法原样保存,反复研究后,参考django-jsonfield写了一版。
原理是,改为继承models.Field类,(继承models.TextField类,则formfield和value_to_string不生效)
数据库依旧将数据库中的yaml文本转为dict/list,在django admin中通过自定义widget显示为yaml字符串格式。
为了保存时,验证表单中yaml字符串格式是否正确,还需要自定义一个form。完整代码如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | import django from django.db import models from django import forms from django.core.exceptions import ValidationError import yaml class YamlWidget(forms.Textarea): def render( self , name, value, attrs = None , renderer = None ): if value is None : value = "" if not isinstance(value, str): value = yaml.safe_dump(value, default_flow_style = False ) if django.VERSION < ( 2 , 0 ): return super().render(name, value, attrs) return super().render(name, value, attrs, renderer) class YamlFormField(forms.CharField): empty_values = [ None , ''] def __init__( self , * args, * * kwargs): if 'widget' not in kwargs: kwargs[ 'widget' ] = YamlWidget super().__init__( * args, * * kwargs) def to_python( self , value): if isinstance(value, str) and value: try : return yaml.safe_load(value) except Exception as exc: raise forms.ValidationError( 'Yaml decode error: %s' % (exc.args[ 0 ],)) else : return value def validate( self , value): if value in self .empty_values and self .required: raise forms.ValidationError( self .error_messages[ 'required' ], code = 'required' ) class YamlField(models.Field): description = "Yaml object" def get_internal_type( self ): return 'TextField' def formfield( self , * * kwargs): defaults = { 'form_class' : YamlFormField, 'widget' : YamlWidget } defaults.update( * * kwargs) return super().formfield( * * defaults) def to_python( self , value: str): # 将数据库内容转为python对象时调用 if value is None : if not self .null and self .blank: return "" return None if isinstance(value, (list, dict)): return value value = yaml.safe_load(value) return value def validate( self , value, model_instance): # 验证从接受到字典格式 if not self .null and value is None : raise ValidationError( self .error_messages[ 'null' ]) try : self .get_prep_value(value) except ValueError: raise ValidationError( self .error_messages[ 'invalid' ] % value) def get_prep_value( self , value: (list, dict)): # 保存时插入数据, 转为字符串存储 if value is None : return None value = yaml.safe_dump(value, default_flow_style = False ) return value def from_db_value( self , value: str, expression, connection, * args, * * kwargs): # 从数据库读取字段是调用 return self .to_python(value) def value_to_string( self , obj): # Rest Framework调用时 return self .value_from_object(obj) |
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。
- 本文固定链接: https://zxbcw.cn/post/199432/
- 转载请注明:必须在正文中标注并保留原文链接
- QQ群: PHP高手阵营官方总群(344148542)
- QQ群: Yii2.0开发(304864863)