Django自定义YamlField实现过程解析


Posted in Python onNovember 11, 2020

需求

在使用django admin时希望后台的Textarea多行文本框可以按yaml格式编写,数据库保存为Text文本类型,字段和接口中读取出来自动变为字典或列表格式。

试过pip install django-yamlfied,修改支持新版django之后

接口中返回的字段是字符串形式,不符合预期。

之前写过一版。

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。完整代码如下。

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)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python海龟绘图实例教程
Jul 24 Python
编写Python的web框架中的Model的教程
Apr 29 Python
Python DataFrame设置/更改列表字段/元素类型的方法
Jun 09 Python
Python通过paramiko远程下载Linux服务器上的文件实例
Dec 27 Python
详解Python基础random模块随机数的生成
Mar 23 Python
Python学习笔记之自定义函数用法详解
Jun 08 Python
Django RBAC权限管理设计过程详解
Aug 06 Python
利用rest framework搭建Django API过程解析
Aug 31 Python
Python高级property属性用法实例分析
Nov 19 Python
Pyecharts 动态地图 geo()和map()的安装与用法详解
Mar 25 Python
Python优秀开源项目Rich源码解析的流程分析
Jul 06 Python
用python对oracle进行简单性能测试
Dec 05 Python
Python监听剪切板实现方法代码实例
Nov 11 #Python
如何通过python计算圆周率PI
Nov 11 #Python
python中turtle库的简单使用教程
Nov 11 #Python
python 怎样进行内存管理
Nov 10 #Python
python tqdm实现进度条的示例代码
Nov 10 #Python
python 解决Windows平台上路径有空格的问题
Nov 10 #Python
Python在后台自动解压各种压缩文件的实现方法
Nov 10 #Python
You might like
IIS7.X配置PHP运行环境小结
2011/06/09 PHP
php使用GD创建保持宽高比缩略图的方法
2015/04/17 PHP
浅谈Yii乐观锁的使用及原理
2017/07/25 PHP
Yii2.0框架behaviors方法使用实例分析
2019/09/30 PHP
JavaScript学习笔记(二) js对象
2011/10/25 Javascript
从零学JS之你需要了解的几本书
2014/05/19 Javascript
jQuery插件分享之分页插件jqPagination
2014/06/06 Javascript
node.js中的fs.exists方法使用说明
2014/12/17 Javascript
纯js实现重发验证码按钮倒数功能
2015/04/21 Javascript
Javascript编程之继承实例汇总
2015/11/28 Javascript
Bootstrap入门教程一Hello Bootstrap初识
2017/03/02 Javascript
Bootstrap表单控件学习使用
2017/03/07 Javascript
node+koa2+mysql+bootstrap搭建一个前端论坛
2018/05/06 Javascript
vue.js图片转Base64上传图片并预览的实现方法
2018/08/02 Javascript
vue增加强缓存和版本号的实现方法
2019/05/01 Javascript
vue 使用axios 数据请求第三方插件的使用教程详解
2019/07/05 Javascript
浅谈vue中使用编辑器vue-quill-editor踩过的坑
2020/08/03 Javascript
python 回调函数和回调方法的实现分析
2016/03/23 Python
简单谈谈python中的Queue与多进程
2016/08/25 Python
python Django里CSRF 对应策略详解
2019/08/05 Python
pycharm部署、配置anaconda环境的教程
2020/03/24 Python
详解前端HTML5几种存储方式的总结
2016/12/27 HTML / CSS
DHC美国官网:日本通信销售第一的化妆品品牌
2017/11/12 全球购物
试述DBMS的主要功能
2016/11/13 面试题
会计专业推荐信
2013/10/29 职场文书
新闻编辑自荐信
2013/11/03 职场文书
就业推荐表自我鉴定范文
2014/03/21 职场文书
环卫工人节活动总结
2014/08/29 职场文书
工程索赔意向书
2014/08/30 职场文书
工作作风整顿个人剖析材料
2014/10/11 职场文书
2014年乡镇人大工作总结
2014/11/25 职场文书
公司捐书倡议书
2015/04/27 职场文书
大学团日活动总结书
2015/05/11 职场文书
2019年12月24日平安夜祝福语集锦
2019/12/24 职场文书
Vue中插槽slot的使用方法与应用场景详析
2021/06/08 Vue.js
联想win10摄像头打不开怎么办?win10笔记本摄像头打不开解决办法
2022/04/08 数码科技