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 相关文章推荐
Python3中多线程编程的队列运作示例
Apr 16 Python
python学习笔记之调用eval函数出现invalid syntax错误问题
Oct 18 Python
python安装模块如何通过setup.py安装(超简单)
May 05 Python
利用python实现对web服务器的目录探测的方法
Feb 26 Python
使用Python的OpenCV模块识别滑动验证码的缺口(推荐)
May 10 Python
django框架model orM使用字典作为参数,保存数据的方法分析
Jun 24 Python
python画图--输出指定像素点的颜色值方法
Jul 03 Python
Django框架创建项目的方法入门教程
Nov 04 Python
python解析多层json操作示例
Dec 30 Python
解决tensorflow由于未初始化变量而导致的错误问题
Jan 06 Python
Python3 获取文件属性的方式(时间、大小等)
Mar 12 Python
python 窃取摄像头照片的实现示例
Jan 08 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实现的QQ空间g_tk加密算法
2015/07/09 PHP
详解WordPress中过滤链接与过滤SQL语句的方法
2015/12/18 PHP
PHP在弹框中获取foreach中遍历的id值并传递给地址栏
2017/06/13 PHP
PHP设计模式之简单工厂和工厂模式实例分析
2019/03/25 PHP
求得div 下 img的src地址的js代码
2007/02/28 Javascript
JavaScript 学习笔记(七)字符串的连接
2009/12/31 Javascript
使用JS实现jQuery的addClass, removeClass, hasClass函数功能
2014/10/31 Javascript
谈谈我对JavaScript中typeof和instanceof的深入理解
2015/12/25 Javascript
使用node.js中的Buffer类处理二进制数据的方法
2016/11/26 Javascript
微信小程序分页加载的实例代码
2017/07/11 Javascript
详解让sublime text3支持Vue语法高亮显示的示例
2017/09/29 Javascript
微信小程序实现折叠与展开文章功能
2018/06/12 Javascript
jQuery中DOM操作原则实例分析
2019/08/01 jQuery
js中!和!!的区别与用法
2020/05/09 Javascript
微信小程序实现上拉加载功能示例【加载更多数据/触底加载/点击加载更多数据】
2020/05/29 Javascript
[09:40]DAC2018 4.5 SOLO赛 MidOne vs Miracle
2018/04/06 DOTA
Python实现的选择排序算法原理与用法实例分析
2017/11/22 Python
用Pygal绘制直方图代码示例
2017/12/07 Python
python学习之matplotlib绘制散点图实例
2017/12/09 Python
浅谈Pandas中map, applymap and apply的区别
2018/04/10 Python
Pycharm 创建 Django admin 用户名和密码的实例
2018/05/30 Python
Python列表生成式与生成器操作示例
2018/08/01 Python
python构建基础的爬虫教学
2018/12/23 Python
处理Selenium3+python3定位鼠标悬停才显示的元素
2019/07/31 Python
docker django无法访问redis容器的解决方法
2019/08/21 Python
TensorFlow实现保存训练模型为pd文件并恢复
2020/02/06 Python
TensorFLow 变量命名空间实例
2020/02/11 Python
常用的HTML5列表标签
2017/06/20 HTML / CSS
干部行政关系介绍信
2014/01/17 职场文书
会计专业大学生职业生涯规划书
2014/02/11 职场文书
小鞋子观后感
2015/06/05 职场文书
企业年会祝酒词
2015/08/11 职场文书
安全伴我行主题班会
2015/08/13 职场文书
CSS布局之浮动(float)和定位(position)属性的区别
2021/09/25 HTML / CSS
Go语言的协程上下文的几个方法和用法
2022/04/11 Golang
Ruby使用Mysql2连接操作MySQL
2022/04/19 Ruby