简单的orm实现

我们在使用各种框架的时候,关于数据库这方面的使用,框架给我们提供了很好的封装,这个就是orm

关系映射

orm的底层无非就是做了关系映射

  1. 数据库的表(table --> 类(class
  2. 记录(record,行数据)--> 对象(object
  3. 字段(field)--> 对象的属性(attribute

ORM设计

字段

首先是字段,每个字段都有很多的字段属性,然后考虑到,每个表的字段可能都不同,为了给他提供更好的拓展性,所以这里我们选择用类来封装

  1. class Field(object):
  2. def __init__(self, name, column_type, primary_key, default):
  3. self.name = name
  4. self.column_type = column_type
  5. self.primary_key = primary_key
  6. self.default = default
  7. class StringField(Field):
  8. def __init__(self,name,
  9. column_type='varchar=(255)',
  10. primary_key=False,
  11. default=None):
  12. super().__init__(name,column_type,primary_key,default)
  13. class IntegerField(Field):
  14. def __init__(self,
  15. name,
  16. column_type='int',
  17. primary_key=False,
  18. default=None):
  19. super().__init__(name, column_type, primary_key, default)

表有表名和字段信息等信息

  1. class Teacher(Models):
  2. print("teacher")
  3. table_name='teacher'
  4. tid = IntegerField(name='tid',primary_key=True)
  5. tname = StringField(name='tname')

为了能更好的展示,dict数据类型更适合我们,所以最后让他继承dict,但是字典取值只能通过key取值,这样不方便,所以我们也要改写他的取值方式为.取值

  1. class Models(dict,metaclass=ModelMetaClass):
  2. print("Models")
  3. def __init__(self,**kwargs):
  4. print(f'Models_init')
  5. super().__init__(self,**kwargs)
  6. def __getattr__(self, item):
  7. return self.get(item,"没有该值")
  8. def __setattr__(self, key, value):
  9. self[key]=value

为了确保我们自己定义表的的时候不会有错误,我们需要加一步,字段的检测步骤,并对字段更好整理

  1. class ModelMetaClass(type):
  2. print("ModelMetaClass")
  3. def __new__(cls,class_name,class_base,class_attrs):
  4. print("ModelMetaClass_new")
  5. #实例化对象的时候也会执行,我们要把这一次拦截掉
  6. if class_name == 'Models':
  7. #为了能让实例化顺利完成,返回一个空对象就行
  8. return type.__new__(cls,class_name,class_base,class_attrs)
  9. #获取表名
  10. table_name = class_attrs.get('table_name',class_name)
  11. #定义一个存主键的的变量
  12. primary_key = None
  13. #定义一个字典存储字段信息
  14. mapping = {}
  15. #name='tid',primary_key=True
  16. #for来找到主键字段
  17. for k,v in class_attrs.items():
  18. #判断信息是否是字段
  19. if isinstance(v,Field):
  20. mapping[k] = v
  21. #寻找主键
  22. if v.primary_key:
  23. if primary_key:
  24. raise TypeError("主键只有一个")
  25. primary_key=v.name
  26. #将重复的键值对删除,因为已经放入了mapping
  27. for k in mapping.keys():
  28. class_attrs.pop(k)
  29. if not primary_key:
  30. raise TypeError("表必须要有一个主键")
  31. class_attrs['table_name']=table_name
  32. class_attrs['primary_key']=primary_key
  33. class_attrs['mapping']=mapping
  34. return type.__new__(cls,class_name,class_base,class_attrs)

数据库操作

数据库操作最好就是放在类里面,然后使用类方法

  1. #查找
  2. @classmethod
  3. def select(cls,**kwargs):
  4. ms=MySQL()
  5. #如果没有参数默认是查询全部的
  6. if not kwargs:
  7. sql='select * from %s'%cls.table_name
  8. res=ms.select(sql)
  9. else:
  10. k = list(kwargs.keys())[0]
  11. v = kwargs.get(k)
  12. sql='select * from %s where %s=?'%(cls.table_name,k)
  13. #防sql注入
  14. sql=sql.replace('?','%s')
  15. res=ms.select(sql,v)
  16. if res:
  17. return [cls(**i) for i in res]
  18. #新增
  19. def save(self):
  20. ms=MySQL()
  21. #存字段名
  22. fields=[]
  23. #存值
  24. values=[]
  25. args=[]
  26. for k,v in self.mapping.items():
  27. #主键自增,不用给他赋值
  28. if not v.primary_key:
  29. fields.append(v.name)
  30. args.append("?")
  31. values.append(getattr(self,v.name))
  32. sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args)))
  33. sql = sql.replace('?','%s')
  34. ms.execute(sql,values)
  35. def update(self):
  36. ms = MySQL()
  37. fields = []
  38. valuse = []
  39. pr = None
  40. for k,v in self.mapping.items():
  41. #获取主键值
  42. if v.primary_key:
  43. pr = getattr(self,v.name,v.default)
  44. else:
  45. fields.append(v.name+'=?')
  46. valuse.append(getattr(self,v.name,v.default))
  47. print(fields,valuse)
  48. sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr)
  49. sql = sql.replace('?',"%s")
  50. ms.execute(sql,valuse)

Mysql连接

  1. import pymysql
  2. class MySQL:
  3. #单例模式
  4. __instance = None
  5. def __new__(cls, *args, **kwargs):
  6. if not cls.__instance:
  7. cls.__instance = object.__new__(cls)
  8. return cls.__instance
  9. def __init__(self):
  10. self.mysql = pymysql.connect(
  11. host='127.0.0.1',
  12. port=3306,
  13. user='root',
  14. database='orm_demo',
  15. password='root',
  16. charset='utf8',
  17. autocommit=True
  18. )
  19. #获取游标
  20. self.cursor = self.mysql.cursor(
  21. pymysql.cursors.DictCursor
  22. )
  23. #查看
  24. def select(self,sql,args=None):
  25. #提交sql语句
  26. self.cursor.execute(sql,args)
  27. #获取查询的结果
  28. res = self.cursor.fetchall()
  29. return res
  30. #提交
  31. def execute(self,sql,args):
  32. #提交语句可能会发生异常
  33. try:
  34. self.cursor.execute(sql,args)
  35. except Exception as e:
  36. print(e)
  37. def close(self):
  38. self.cursor.close()
  39. self.mysql.close()

整体代码部分

MySQL.py

  1. import pymysql
  2. class MySQL:
  3. #单例模式
  4. __instance = None
  5. def __new__(cls, *args, **kwargs):
  6. if not cls.__instance:
  7. cls.__instance = object.__new__(cls)
  8. return cls.__instance
  9. def __init__(self):
  10. self.mysql = pymysql.connect(
  11. host='127.0.0.1',
  12. port=3306,
  13. user='root',
  14. database='orm_demo',
  15. password='root',
  16. charset='utf8',
  17. autocommit=True
  18. )
  19. #获取游标
  20. self.cursor = self.mysql.cursor(
  21. pymysql.cursors.DictCursor
  22. )
  23. #查看
  24. def select(self,sql,args=None):
  25. #提交sql语句
  26. self.cursor.execute(sql,args)
  27. #获取查询的结果
  28. res = self.cursor.fetchall()
  29. return res
  30. #提交
  31. def execute(self,sql,args):
  32. #提交语句可能会发生异常
  33. try:
  34. self.cursor.execute(sql,args)
  35. except Exception as e:
  36. print(e)
  37. def close(self):
  38. self.cursor.close()
  39. self.mysql.close()

orm.py

  1. from MySQL import MySQL
  2. # 定义字段类
  3. class Field(object):
  4. def __init__(self, name, column_type, primary_key, default):
  5. self.name = name
  6. self.column_type = column_type
  7. self.primary_key = primary_key
  8. self.default = default
  9. class StringField(Field):
  10. def __init__(self,name,
  11. column_type='varchar=(255)',
  12. primary_key=False,
  13. default=None):
  14. super().__init__(name,column_type,primary_key,default)
  15. class IntegerField(Field):
  16. def __init__(self,
  17. name,
  18. column_type='int',
  19. primary_key=False,
  20. default=None):
  21. super().__init__(name, column_type, primary_key, default)
  22. class ModelMetaClass(type):
  23. print("ModelMetaClass")
  24. def __new__(cls,class_name,class_base,class_attrs):
  25. print("ModelMetaClass_new")
  26. #实例化对象的时候也会执行,我们要把这一次拦截掉
  27. if class_name == 'Models':
  28. #为了能让实例化顺利完成,返回一个空对象就行
  29. return type.__new__(cls,class_name,class_base,class_attrs)
  30. #获取表名
  31. table_name = class_attrs.get('table_name',class_name)
  32. #定义一个存主键的的变量
  33. primary_key = None
  34. #定义一个字典存储字段信息
  35. mapping = {}
  36. #name='tid',primary_key=True
  37. #for来找到主键字段
  38. for k,v in class_attrs.items():
  39. #判断信息是否是字段
  40. if isinstance(v,Field):
  41. mapping[k] = v
  42. #寻找主键
  43. if v.primary_key:
  44. if primary_key:
  45. raise TypeError("主键只有一个")
  46. primary_key=v.name
  47. #将重复的键值对删除,因为已经放入了mapping
  48. for k in mapping.keys():
  49. class_attrs.pop(k)
  50. if not primary_key:
  51. raise TypeError("表必须要有一个主键")
  52. class_attrs['table_name']=table_name
  53. class_attrs['primary_key']=primary_key
  54. class_attrs['mapping']=mapping
  55. return type.__new__(cls,class_name,class_base,class_attrs)
  56. class Models(dict,metaclass=ModelMetaClass):
  57. print("Models")
  58. def __init__(self,**kwargs):
  59. print(f'Models_init')
  60. super().__init__(self,**kwargs)
  61. def __getattr__(self, item):
  62. return self.get(item,"没有该值")
  63. def __setattr__(self, key, value):
  64. self[key]=value
  65. #查找
  66. @classmethod
  67. def select(cls,**kwargs):
  68. ms=MySQL()
  69. #如果没有参数默认是查询全部的
  70. if not kwargs:
  71. sql='select * from %s'%cls.table_name
  72. res=ms.select(sql)
  73. else:
  74. k = list(kwargs.keys())[0]
  75. v = kwargs.get(k)
  76. sql='select * from %s where %s=?'%(cls.table_name,k)
  77. #防sql注入
  78. sql=sql.replace('?','%s')
  79. res=ms.select(sql,v)
  80. if res:
  81. return [cls(**i) for i in res]
  82. #新增
  83. def save(self):
  84. ms=MySQL()
  85. #存字段名
  86. fields=[]
  87. #存值
  88. values=[]
  89. args=[]
  90. for k,v in self.mapping.items():
  91. #主键自增,不用给他赋值
  92. if not v.primary_key:
  93. fields.append(v.name)
  94. args.append("?")
  95. values.append(getattr(self,v.name))
  96. sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args)))
  97. sql = sql.replace('?','%s')
  98. ms.execute(sql,values)
  99. def update(self):
  100. ms = MySQL()
  101. fields = []
  102. valuse = []
  103. pr = None
  104. for k,v in self.mapping.items():
  105. #获取主键值
  106. if v.primary_key:
  107. pr = getattr(self,v.name,v.default)
  108. else:
  109. fields.append(v.name+'=?')
  110. valuse.append(getattr(self,v.name,v.default))
  111. print(fields,valuse)
  112. sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr)
  113. sql = sql.replace('?',"%s")
  114. ms.execute(sql,valuse)
  115. class Teacher(Models):
  116. print("teacher")
  117. table_name='teacher'
  118. tid = IntegerField(name='tid',primary_key=True)
  119. tname = StringField(name='tname')
  120. if __name__ == '__main__':
  121. # tea=Teacher(tname="haha")
  122. tea2=Teacher(tname="haha",tid=5)
  123. # print(Teacher.select(tid=1))
  124. # Teacher.save(tea)
  125. print(Teacher.update(tea2))

简单ORM的实现的更多相关文章

  1. 简单ORM工具的设计和编写,自己项目中曾经用过的

    http://www.cnblogs.com/szp1118/archive/2011/03/30/ORM.html 在之前的一个项目中自己编写了一个简单的ORM小工具,这次重新整理和重构了一下代码, ...

  2. iOS:Core Data 中的简单ORM

    我们首先在xcdatamodel文件中设计我们的数据库:例如我建立一个Data的实体,里面有一个String类型的属性name以及一个Integer类型的num: 然后选中Data,添加文件,选择NS ...

  3. java基础强化——深入理解java注解(附简单ORM功能实现)

    目录 1.什么是注解 2. 注解的结构以及如何在运行时读取注解 2.1 注解的组成 2.2 注解的类层级结构 2.3 如何在运行时获得注解信息 3.几种元注解介绍 3.1 @Retention 3.2 ...

  4. 实现简单ORM案例

    ORM框架: • 我们希望设计一个可以实现对象和SQL自动映射的框架,但是整体用法和设计比Hibernate简单.砍掉不必要的功能.• 会穿插使用设计模式• 增加 – 将对象对应成sql语句,执行sq ...

  5. 封装JDBC:实现简单ORM框架lfdb

    作者:Vinkn 来自http://www.cnblogs.com/Vinkn/ 一.简介 框架就是一组可重用的构件,LZ自己写的姑且就叫微型小框架:lfdb.LZ也对其他的ORM框架没有什么了解,现 ...

  6. JAVA描述的简单ORM框架

    抽了点时间自己写了个ORM,主要是为了复习JAVA泛型,映射,注解方面的知识.如需代码,可前往:https://github.com/m2492565210/java_orm自行下载 框架的类结构如下 ...

  7. JDBC 利用反射技术将查询结果封装为对象(简单ORM实现)

    ORM(Object Relational Mapping)对象关系映射 public class ORMTest { public static void main(String[] args) t ...

  8. python-元类和使用元类实现简单的ORM

    元类 面向对象中,对象是类的实例,即对象是通过类创建出来的,在python中,一切皆对象,同样,类也是一个对象,叫做类对象,只是这个类对象拥有创建其子对象(实例对象)的能力.既然类是对象,那么类是通过 ...

  9. 终于等到你:CYQ.Data V5系列 (ORM数据层)最新版本开源了

    前言: 不要问我框架为什么从收费授权转到免费开源,人生没有那么多为什么,这些年我开源的东西并不少,虽然这个是最核心的,看淡了就也没什么了. 群里的网友:太平说: 记得一年前你开源另一个项目的时候我就说 ...

随机推荐

  1. winform 数据库资料导出Excel方法(适用于资料数据较多加载慢,不用呈现至DatagridView)

    Private Sub savefile(ByVal dgv2 As DataTable) Dim app As Object = CreateObject("Excel.Applicati ...

  2. CMMS系统中的物联监测

    有条件的设备物联后,可时实查看设备运行状态,如发现异常,可提前干预.

  3. Go netpoll I/O 多路复用构建原生网络模型之源码深度解析

    导言 Go 基于 I/O multiplexing 和 goroutine 构建了一个简洁而高性能的原生网络模型(基于 Go 的I/O 多路复用 netpoll),提供了 goroutine-per- ...

  4. CSPS模拟测试59

    这场考得我心态爆炸......... 开场T1只会$n^{2}$,然后发现bfs时每个点只需要被更新一次,其他的更新都是没用的. 也就是说,我们可以只更新还没被更新的点? 于是我先YY了一个链表,发现 ...

  5. 实现两个数字的交换(C语言)

    int num1=10; int num2=20; //1.简单的数学方法实现数字交换 num1=num1+num2;//num1=30 num2=num1-num2;//num2=10 num1=n ...

  6. win10 visual studio 2017环境中安装CUDA8

    从https://developer.nvidia.com/cuda-toolkit-archive下载CUDA 8 安装 从https://developer.nvidia.com/gamework ...

  7. nyoj 274-正三角形的外接圆面积 (R = PI * a * a / 3)

    274-正三角形的外接圆面积 内存限制:64MB 时间限制:1000ms 特判: No 通过数:14 提交数:22 难度:0 题目描述: 给你正三角形的边长,pi=3.1415926 ,求正三角形的外 ...

  8. VLAN实验(1)Access接口

    1.选择两台S3700的交换机,5台PC机,并按照下图链接好并填写IP,完成此拓扑图 2.由于现在我们还没有划分VLAN,这5台PC,还在同一个VLAN中,现在我们启动所有的设备,这是所有的主机应该是 ...

  9. Pashmak and Buses(构造)

    题目链接:http://codeforces.com/problemset/problem/459/C 题意:n个人, k辆车, d天,每天将所有 任意人安排到k辆车, 问怎样安排, 可时不存在 2人 ...

  10. php5.6开启curl

    1.   打开php安装目录,打开ext目录,是否有php_curl.dll扩展文件,如果没有该扩展文件,请在网上下载此文件. 2.   打开php.ini,找到  ;extension=php_cu ...