ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。

要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。

让我们来尝试编写一个ORM框架。

编写底层模块的第一步,就是先把调用接口写出来。比如,使用者如果使用这个ORM框架,想定义一个User类来操作对应的数据库表User,我们期待他写出这样的代码:

期望代码

class User(Model): # User类,继承Model

# 定义类的属性到列的映射: 右边的 StringField(‘username’),这里StringField是类,类(‘username’)是输入__init__绑定的参数,所以得到的是一个实例,正好对应value

id = IntegerField('id') # ⚠️id理解为一个变量不好,id理解成一个key最恰当,=右边的则是value,这里对应的就是数据库字典的id数据

name = StringField('username') # name是类属性,具体可参考类属性与实例属性定义,类调用属性就是User.name

email = StringField('email') # id name email password 均是User的属性,User的实例可以直接调用

password = StringField('password') # User().name = StringField(‘username’),直接调用,也就是对应一个user的表,表里的name叫SF()

# 创建一个实例:

u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') # ⚠️对照这个效果可以想通一二了

# 保存到数据库:

u.save()

其中,父类Model和属性类型StringField、IntegerField是由ORM框架提供的,剩下的魔术方法比如save()全部由metaclass自动完成。虽然metaclass的编写会比较复杂,但ORM的使用者用起来却异常简单。

现在,我们就按上面的接口来实现该ORM。

首先来定义Field类,它负责保存数据库表的字段名和字段类型

class Field(object): # 对应数据库中保存的字段名和字段类型

def __init__(self, name, column_type): # 添加__init__(self,name)方法后,类的实例必须是StringField(‘某name’),正好呼应上方的期望代码

self.name = name # 字段名

self.column_type = column_type # 字段类型

def __str__(self): # 输入print(xxx)会自动调用__str__,它为了使打印结果更好看而已,Python 定义了__str__()和__repr__()两种方法,__str__()用于显示给用户,而__repr__()用于显示给开发人员。

return '' % (self.__class__.__name__, self.name) # 不使用print(xxx)而是直接输入实例xxx,则该行不会打印显示出来,看起来就很丑

在Field的基础上,进一步定义各种类型的Field,比如StringField,IntegerField等等:

class StringField(Field): # ✌️通过比对测试,StringField.name = name, StringField.column_type = varchar(100).

def __init__(self, name): # 实例属性,`实例.name`调用

super(StringField, self).__init__(name, 'varchar(100)') # 为什么这么设计?super最后跟的参数是(name,’varchar(100)’)一个变量name,一个值。为了就是不让人去修改 column_type这个参数而已

# ⚠️super的用法,继承父类的方法而自己无需定义, super(StringFileld,self).__init__这段是套路,都一样,super后面跟的子类名+self,只有最后的(name,’varchar(100)’)表示继承父类的哪些属性

------------------------测试------------------------------

In [67]: test = StringField('love')

In [68]: type(test)

Out[68]: __main__.StringField

In [70]: test.column_type

Out[70]: 'varchar(100)'

In [71]: test.name

Out[71]: 'love'

------------------------------------------------------------

class IntegerField(Field): # ⚠️子类继承这些方法

def __init__(self, name):

super(IntegerField, self).__init__(name, 'bigint') # __init__()这样的写法,可参考我的super文章

下一步,就是编写最复杂的ModelMetaclass了:(重点 难)

class ModelMetaclass(type):

# 元类必须实现__new__方法,当一个类指定通过某元类来创建,那么就会调用该元类的__new__方法

# 该方法接收4个参数

# cls为当前准备创建的类的对象

# name为类的名字,创建User类,则name便是User

# bases类继承的父类集合,创建User类,则base便是Model

#

python元类 orm_python-进阶-元类在ORM上的应用详解相关推荐

  1. python类继承中构造方法_第8.3节 Python类的__init__方法深入剖析:构造方法与继承详解...

    第8.3节Python类的__init__方法深入剖析:构造方法与继承详解 一.    引言 上两节介绍了构造方法的语法及参数,说明了构造方法是Python的类创建实例后首先执行的方法,并说明如果类没 ...

  2. C++ - 派生类(derived class) 的 构造(construct) 和 析构(destruct)顺序 详解

    派生类(derived class) 的 构造(construct) 和 析构(destruct)顺序 详解 本文地址: http://blog.csdn.net/caroline_wendy/art ...

  3. Scala进阶之路-面向对象编程之类的成员详解

    Scala进阶之路-面向对象编程之类的成员详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Scala中的object对象及apply方法 1>.scala 单例对象 ...

  4. python调用shell脚本的参数_使用python执行shell脚本 并动态传参 及subprocess的使用详解

    最近工作需求中 有遇到这个情况 在web端获取配置文件内容 及 往shell 脚本中动态传入参数 执行shell脚本这个有多种方法 最后还是选择了subprocess这个python标准库 subpr ...

  5. python计算各类型电影的评分_【Python数据科学实战项目】之 基于MovieLens的影评趋势分析|详解...

    原标题:[Python数据科学实战项目]之 基于MovieLens的影评趋势分析|详解 注:图片源于https://movielens.org/ 1. 项目任务 1.1 数据来源 本项目使用Group ...

  6. 基于点击量的趋势分析python_【Python数据科学实战项目】之 基于MovieLens的影评趋势分析详解...

    原标题:[Python数据科学实战项目]之 基于MovieLens的影评趋势分析详解 本文转自: 数据科学DataScience 注:图片源于https://movielens.org/ 1. 项目任 ...

  7. [python opencv 计算机视觉零基础到实战] 四、了解色彩空间及其详解

    一.学习目标 了解什么是色彩空间 了解opencv中色彩空间的转换 目录 [python opencv 计算机视觉零基础到实战] 一.opencv的helloworld [[python opencv ...

  8. python整数池_对Python中小整数对象池和大整数对象池的使用详解

    1. 小整数对象池 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间. Python 对小整数的定义是 [-5, 256] 这些整数对象是提 ...

  9. 站长在线Python精讲:在Python中使用split()方法分割、使用join()方法合并字符串详解

    欢迎你来到站长在线的站长学堂学习Python知识,本文学习的是<在Python中使用split()方法分割.使用join()方法合并字符串详解>.本知识点主要内容有:在Python中使用s ...

最新文章

  1. pandas.describe()参数含义
  2. Linux线程-互斥锁pthread_mutex_t
  3. 皮一皮:直男只想说一句,表白?是表特别白吗?
  4. android 去掉蓝牙传输文件功能_iPhone还在用蓝牙传输照片?这个功能更好用还快哟,了解一下...
  5. 深度学习(十)keras学习笔记
  6. iOS开发 适配iOS10以及Xcode8-b
  7. 知乎:全球发售2600万股销售股份 每股发售价51.8港元
  8. Apache CXF实战之七 使用Web Service传输文件
  9. 学考语言成绩c对高考有影响吗_广东2020学考招录办法来了,实现平行志愿,计划不低于年度总计划50%...
  10. 1 恢复MySQL误删数据
  11. JDK1.8源码(十一)——java.util.TreeMap类
  12. SAP 服务器文件上传和下载
  13. 利用Excel制作库房管理系统
  14. 人工智能万亿市场待挖掘
  15. Topaz Gigapixel AI打开软件闪退及加载图片闪退 解决办法
  16. 盒式滤波器BoxFilter
  17. 安卓投屏传输手机声音到电脑最简单的方式
  18. C语言输入一个日期,计算这一天是周几
  19. 图片存放在服务器还是数据库里的解释?
  20. r语言list 转换成 vector

热门文章

  1. MySQL从入门到搞定实战
  2. html旋转墙壁效果,css3实现照片墙效果,鼠标悬浮时旋转放大并摆正
  3. 龙格库塔法解微分方程组的matlab程序,MATLAB实例源码教程:龙格库塔法求解微分方程组源代码实例.doc...
  4. Redis入门教程(一)
  5. php查询当前session,php查看当前Session的ID方法
  6. gdb coredump
  7. hdfs文档存储服务器,一文读懂HDFS分布式存储框架分析
  8. 有没有可以翻译c语言程序的软件下载,程序员秒懂!分享一款很优雅的翻译软件...
  9. php 如何把u5fb,php如何将json中的unicode编码转为汉字?
  10. bootstrap的php写在哪里,bootstrap用什么编辑器写