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学习之asyncore模块用法实例教程
Sep 29 Python
python持久性管理pickle模块详细介绍
Feb 18 Python
Python实现的维尼吉亚密码算法示例
Apr 12 Python
Python3实现的Mysql数据库操作封装类
Jun 06 Python
win10下python3.5.2和tensorflow安装环境搭建教程
Sep 19 Python
Python命名空间的本质和加载顺序
Dec 17 Python
Python多线程原理与用法实例剖析
Jan 22 Python
Django页面数据的缓存与使用的具体方法
Apr 23 Python
Python 获取ftp服务器文件时间的方法
Jul 02 Python
twilio python自动拨打电话,播放自定义mp3音频的方法
Aug 08 Python
简单介绍django提供的加密算法
Dec 18 Python
Python 实现劳拉游戏的实例代码(四连环、重力四子棋)
Mar 03 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
PHP仿博客园 个人博客(2) 数据库增添改删
2013/07/05 PHP
php生成图形(Libchart)实例
2013/11/06 PHP
PHP中的use关键字概述
2014/07/23 PHP
php-app开发接口加密详解
2018/04/18 PHP
PHP如何搭建百度Ueditor富文本编辑器
2018/09/21 PHP
定义JavaScript二维数组采用定义数组的数组来实现
2012/12/09 Javascript
将list转换为json失败的原因
2013/12/17 Javascript
JS控制弹出新页面窗口位置和大小的方法
2015/03/02 Javascript
js中日期的加减法
2015/05/06 Javascript
javascript实现状态栏文字首尾相接循环滚动的方法
2015/07/22 Javascript
详解使用angular-cli发布i18n多国语言Angular应用
2017/05/20 Javascript
关于react中组件通信的几种方式详解
2017/12/10 Javascript
原生js实现移动端触摸轮播的示例代码
2017/12/22 Javascript
vue获取当前点击的元素并传值的实例
2018/03/09 Javascript
Angular HMR(热模块替换)功能实现方法
2018/04/04 Javascript
React 组件间的通信示例
2018/06/14 Javascript
Layui实现数据表格默认全部显示(不要分页)
2019/10/26 Javascript
Python实现的一个自动售饮料程序代码分享
2014/08/25 Python
在Python中使用pngquant压缩png图片的教程
2015/04/09 Python
Python中的日期时间处理详解
2016/11/17 Python
详解Python中的相对导入和绝对导入
2017/01/06 Python
简单实现Python爬取网络图片
2018/04/01 Python
Python实现正整数分解质因数操作示例
2018/08/01 Python
Python爬虫将爬取的图片写入world文档的方法
2018/11/07 Python
利用Python半自动化生成Nessus报告的方法
2019/03/19 Python
Python查找不限层级Json数据中某个key或者value的路径方式
2020/02/27 Python
使用CSS3在触屏上为按钮实现激活效果
2013/09/27 HTML / CSS
html5 datalist标签使用示例(自动完成组件)
2014/05/04 HTML / CSS
开会迟到检讨书
2014/01/08 职场文书
户外活动策划方案
2014/03/12 职场文书
《最大的麦穗》教学反思
2014/04/17 职场文书
答谢词范文
2015/01/05 职场文书
《落花生》教学反思
2016/02/16 职场文书
奖学金发言稿(范文)
2019/08/21 职场文书
致男子1500米运动员的广播稿
2019/11/08 职场文书
Apache SeaTunnel实现 非CDC数据抽取
2022/05/20 Servers