一、需求背景:

django的models模块提供了很多数据字段的数据类型field,但是总有写奇葩需求不能依靠默认字段满足,所以需要自定义数据数据库数据字段类型。所有的自定义field应该在app路径下的fields.py文件里面定义。

二、自定义数据库数据类型字段:

1、知识点1->继承自filed类型

所以所有自定义类型都应该如下编写:

 from django.db import models

 class myfiled(models.Filed):
pass

第一行引入继承的父类所在的models模块,然后定义自定义field类型,定义时候继承models.field类。

2、可以创建一个描述变量

 from django.db import models

 class myfield(models.Field):
description = "This is my own field!"

3、初始化实例的构造函数

 class myfield(models.Field):
def __init__(self,*args,**kwargs):
kwargs['max_length'] = 100
super(myfield,self).__init__(*args,**kwargs)

这个函数可以不显性定义

4、对于1.7之前版本的django的自定义field迁移到1.7以及之后的版本,需要自定义deconsturct函数,但这里不在本文的介绍访问之内。

5、实现db_type方法,作用是返回其本身说属于的数据库中的字段数据类型,例如你自定义了一个时间类型,那么对应在MySQL中就是datetime类型。

 def db_type(self,connection):

     if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
return 'datetime'
else:
return 'timestamp'

这里的connection.setting_dict是一个保存着连接配置的字典数据结构,其中ENGINE表示的是数据库类型,django.db.backends.mysql就是mysql,其实,这里就相当于定义了你自定义数据字段类型说依赖的数据库数据字段类型,如果对长度要限制,则可以在实例化出事函数中,传入max_length值给属性,self.max_length属性,然后,在db_type里面初始化,完成动态构造。

 class myfield(models.Field):
def __init__(self,max_length,*args,**kwargs):
self.max_length = max_length
super(myfield,self).__init__(*args,**kwargs)
def db_type(self):
return 'int(%s)'%self.max_length

6、如果需要自定义某个column,最好还是去数据库中使用sql语句创建或其他方式,请在db_type函数中返回None,通知migerate创建数据库表的时候跳过这个字段,因为migerate就是利用这个返回值来创建数据库表的。当然有些时候也可以使用另外一个函数:get_internal_type

 def get_internal_type(self):
return 'CharField'

7、增删改查时候需要用到的几个API:

(1)将值转换为python对象:

这里有两个api需要实现from_db_value()和to_python()

引用官方文档中的一段内容来解释一下:

如果您的自定义Field类处理比字符串,日期,整数或浮点数更复杂的数据结构,则可能需要覆盖from_db_value()to_python()

如果存在于字段子类,则在从数据库加载数据(包括在聚合和values()调用)的所有情况下将调用from_db_value()

to_python()通过反序列化和从表单使用的clean()方法调用。

作为一般规则,to_python()应优雅地处理以下任何参数:

  • 正确类型的实例
  • 字符串
  • None(如果字段允许null=True

尤其请注意to_python通过反序列化和表单中的clean方法调用,这个要注意反序列化的问题,python的反序列化是一个比较严重的安全问题。

所以一般的这两个函数一般的定义范式:

 def from_db_value(self,value,expression,connection,content):
if value is None:
return value
try:
return field_function(value)
except Exception:
return value def to_python(self,value):
if value is None or isinstance(value,xxxx):
return value
try:
return field_function(value)
except Exception:
return value

当然field_function是对value的处理函数,需要自己定义。

(2)将python对象转换为查询值:

当重写to_python的时候,必须重写get_prep_value函数,基本上是field_function函数的逆向操作

 def get_prep_value(self,value):
return do_something(value)

(3)将查询值转换为数据库值:

也就是类似像这一类操作的转换过程(p.s.日期存在数据库中是unix时间戳,后台处理是2018-01-01 11:07:23.123),都写在get_db_prep_value函数中

 def get_db_prep_value(self, value, connection, prepared=False):
return do_something(value)

(4)此外还有很多API方法,详情请参考http://python.usyiyi.cn/documents/django_182/ref/models/fields.html

8、与表单相关可以覆盖重写formfield,此处不再展开。

9、关于序列化,这里要展开引一段官方文档:

转换字段数据以进行序列化

要自定义序列化程序如何序列化值,您可以覆盖value_to_string()。调用Field._get_val_from_obj(obj)是获取值序列化的最佳方式。例如,由于我们的HandField使用字符串作为其数据存储,我们可以重用一些现有的转换代码:

class HandField(models.Field):
# ... def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_prep_value(value)

这里值得注意。

Django学习笔记第十二篇--关于自定义数据库字段数据类型的更多相关文章

  1. Python框架之Django学习笔记(十二)

    Django站点管理 十一转眼结束,说好的充电没能顺利开展,反而悠闲的看了电视剧以及去影院看了新上映的<心花路放>.<亲爱的>以及<黄金时代>,说好的劳逸结合现在回 ...

  2. MyCat 学习笔记 第十二篇.数据分片 之 分片事务处理

    1 环境说明 VM 模拟3台MYSQL 5.6 服务器 VM1 192.168.31.187:3307 VM2 192.168.31.212:3307 VM3 192.168.31.150:  330 ...

  3. VSTO 学习笔记(十二)自定义公式与Ribbon

    原文:VSTO 学习笔记(十二)自定义公式与Ribbon 这几天工作中在开发一个Excel插件,包含自定义公式,根据条件从数据库中查询结果.这次我们来做一个简单的测试,达到类似的目的. 即在Excel ...

  4. 汇编入门学习笔记 (十二)—— int指令、port

    疯狂的暑假学习之  汇编入门学习笔记 (十二)--  int指令.port 參考: <汇编语言> 王爽 第13.14章 一.int指令 1. int指令引发的中断 int n指令,相当于引 ...

  5. Binder学习笔记(十二)—— binder_transaction(...)都干了什么?

    binder_open(...)都干了什么? 在回答binder_transaction(...)之前,还有一些基础设施要去探究,比如binder_open(...),binder_mmap(...) ...

  6. Egret入门学习日记 --- 第十二篇(书中 5.1节 内容)

    第十二篇(书中 5.1节 内容) 昨天把 第4章完成了. 今天来看第5章. 接下来是 5.1节 的内容. 总结一下 5.1节 的重点: 1.如何制作一个公用按钮皮肤. 跟着做: 重点1:如何制作一个公 ...

  7. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  8. MySQL数据库学习笔记(十二)----开源工具DbUtils的使用(数据库的增删改查)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  9. Android学习笔记(十二)——实战:制作一个聊天界面

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 运用简单的布局知识,我们可以来尝试制作一个聊天界面. 一.制作 Nine-Patch 图片 : Nine-Pa ...

随机推荐

  1. hive 分位数函数 percentile(col, p)

    注意在偶数情况下,中位数会存在小数,特别注意! hive里面倒是有个percentile函数和percentile_approx函数,其使用方式为percentile(col, p).percenti ...

  2. unity, inspector listview

    inspector中实现列表框: public override void OnInspectorGUI(){ bool isDoubleClick=false;        Event e = E ...

  3. 使用libjpeg 压缩yuv420到jpg (内存方式)

    #include <Windows.h> #include <stdio.h> extern "C" { #include <jpeglib.h> ...

  4. EAV/ESS 8.x 自定义服务器正确方法+更新服务器列表

    下面用64位的ESET Smart Security 8.0.319.1进行设置自定义更新服务器说明(注:修改方法32位和64位通用) 1.  让我们先看一下ESET Smart Security 8 ...

  5. sql语句判断是否为数字、字母、中文

    1. sql语句判断是否为数字.字母.中文 select ascii(字段) 数字:48-57字母:65-123汉字:123+ 如,要删除某个全为数字的字段 DELETE FROM table  WH ...

  6. Linux系统下Shell命令行快捷键实用技巧

    # Ctrl + A# Ctrl + E切到命令行开始|结尾 # esc+f往右跳一个词# esc+b往左跳一个词 # Ctrl + W清除光标之前一个单词# esc + d 删除光标后的一个词 # ...

  7. 浏览器 本地预览图片 window.url.createobjecturl

    第一种方式 <script type="text/javascript"> function setImagePreview() { var docObj = docu ...

  8. linux中mysql安装的问题

    Starting MySQL.Manager of pid-file quit without updating file.[FAILED] 已解决 这是由于系统中/etc/my.cnf文件本身存在或 ...

  9. netifd

    Netifd是OpenWrt中用于进行网络配置的守护进程,基本上所有网络接口设置以及内核的netlink事件都可以由netifd来处理完成. 在启动netifd之前用户需要将所需的配置写入uci配置文 ...

  10. DRBD(Distributed Replicated Block Device) 分布式块设备复制 进行集群高可用方案

    DRBD是一个用软件实现的.无共享的.服务器之间镜像块设备内容的存储复制解决方案. 外文名 DRBD drbdadm 高级管理工具 drbdsetup 置装载进kernel的DRBD模块 drbdme ...