一、需求背景:

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. Ruby入门笔记

    Ruby入门笔记 一切皆为对象 “Hello”.length 方法 定义:def开头 end结尾 命名一般采用下划线分隔单词

  2. CXF学习笔记 之 “注解”

    @WebService 1.serviceName: 对外发布的服务名,指定 Web Service 的服务名称:wsdl:service.缺省值为 Java 类的简单名称 + Service.(字符 ...

  3. Linux下编译C++程序遇到错误:undefined reference to `*::*

    “undefined reference to”的意思是,该函数未定义. 如果使用的是g++,有以下检查方案: 如果提示未定义的函数是某个库的函数.检查库是否已经安装,并在编译命令中采用-l和-L参数 ...

  4. 由于link顺序错误导致的undefined reference

    其实我之前就遇到过这个问题,也强调过,GNU-G++在link阶段是依赖输入的.o或者.a文件的顺序的.如果顺序错误会导致undefined reference错误 见这篇随笔:http://www. ...

  5. mybatis、ibatis 和spring集成

    mybatis是ibatis的升级版,spring也有自带mybatis的orm.所以,搭建ibatis的框架也会有多种方式(我这里mybatis是3.0的,ibatis是2.3的,spring是3. ...

  6. Android开发艺术探索读书笔记——进程间通信

    1. 多进程使用场景 1) 应用某些模块由于特殊需求须要执行在单独进程中. 如消息推送,使消息推送进程与应用进程能单独存活,消息推送进程不会由于应用程序进程crash而受影响. 2) 为加大一个应用可 ...

  7. scala flatMap reduceLeft foldLeft

    object collection_t1 { def flatMap1(): Unit = { val li = List(,,) val res = li.flatMap(x => x mat ...

  8. Linux下HTTP Server

    想在Linux下实现一个简单的web Server并不难.一个最简单的HTTP Server不过是一个高级的文件服务器,不断地接收客户端(浏览器)发送的HTTP请求,解析请求,处理请求,然后像客户端回 ...

  9. Hadoop环境搭载

    官网安装教程:[http://archive.cloudera.com/cdh5/cdh/5/hadoop-2.6.0-cdh5.13.0/hadoop-project-dist/hadoop-com ...

  10. MySQL5.0、5.1、5.5、5.6功能进化

    目前线上使用的版本情况:新上线端口统一使用5.5,不说别的,一个快速恢复重启就值回票价. 但因为历史原因还有大量5.1的版本,甚至,I’am sorry,还有少数5.0的版本. 至于5.0以前的版本, ...