简单的orm实现

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

关系映射

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

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

ORM设计

字段

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

class Field(object):
def __init__(self, name, column_type, primary_key, default):
self.name = name
self.column_type = column_type
self.primary_key = primary_key
self.default = default class StringField(Field):
def __init__(self,name,
column_type='varchar=(255)',
primary_key=False,
default=None):
super().__init__(name,column_type,primary_key,default) class IntegerField(Field):
def __init__(self,
name,
column_type='int',
primary_key=False,
default=None):
super().__init__(name, column_type, primary_key, default)

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

class Teacher(Models):
print("teacher")
table_name='teacher'
tid = IntegerField(name='tid',primary_key=True)
tname = StringField(name='tname')

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

class Models(dict,metaclass=ModelMetaClass):
print("Models")
def __init__(self,**kwargs):
print(f'Models_init')
super().__init__(self,**kwargs) def __getattr__(self, item):
return self.get(item,"没有该值") def __setattr__(self, key, value):
self[key]=value

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

class ModelMetaClass(type):
print("ModelMetaClass")
def __new__(cls,class_name,class_base,class_attrs):
print("ModelMetaClass_new")
#实例化对象的时候也会执行,我们要把这一次拦截掉
if class_name == 'Models':
#为了能让实例化顺利完成,返回一个空对象就行
return type.__new__(cls,class_name,class_base,class_attrs)
#获取表名
table_name = class_attrs.get('table_name',class_name) #定义一个存主键的的变量
primary_key = None #定义一个字典存储字段信息
mapping = {} #name='tid',primary_key=True
#for来找到主键字段
for k,v in class_attrs.items():
#判断信息是否是字段
if isinstance(v,Field):
mapping[k] = v
#寻找主键
if v.primary_key:
if primary_key:
raise TypeError("主键只有一个")
primary_key=v.name #将重复的键值对删除,因为已经放入了mapping
for k in mapping.keys():
class_attrs.pop(k)
if not primary_key:
raise TypeError("表必须要有一个主键")
class_attrs['table_name']=table_name
class_attrs['primary_key']=primary_key
class_attrs['mapping']=mapping
return type.__new__(cls,class_name,class_base,class_attrs)

数据库操作

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

    #查找
@classmethod
def select(cls,**kwargs):
ms=MySQL() #如果没有参数默认是查询全部的
if not kwargs:
sql='select * from %s'%cls.table_name
res=ms.select(sql)
else:
k = list(kwargs.keys())[0]
v = kwargs.get(k)
sql='select * from %s where %s=?'%(cls.table_name,k) #防sql注入
sql=sql.replace('?','%s') res=ms.select(sql,v)
if res:
return [cls(**i) for i in res] #新增
def save(self):
ms=MySQL() #存字段名
fields=[]
#存值
values=[]
args=[] for k,v in self.mapping.items():
#主键自增,不用给他赋值
if not v.primary_key:
fields.append(v.name)
args.append("?")
values.append(getattr(self,v.name)) sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args))) sql = sql.replace('?','%s') ms.execute(sql,values) def update(self):
ms = MySQL()
fields = []
valuse = []
pr = None
for k,v in self.mapping.items():
#获取主键值
if v.primary_key:
pr = getattr(self,v.name,v.default)
else:
fields.append(v.name+'=?')
valuse.append(getattr(self,v.name,v.default))
print(fields,valuse)
sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr) sql = sql.replace('?',"%s") ms.execute(sql,valuse)

Mysql连接

import pymysql

class MySQL:

    #单例模式
__instance = None def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance def __init__(self):
self.mysql = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
database='orm_demo',
password='root',
charset='utf8',
autocommit=True
) #获取游标
self.cursor = self.mysql.cursor(
pymysql.cursors.DictCursor
) #查看
def select(self,sql,args=None):
#提交sql语句
self.cursor.execute(sql,args) #获取查询的结果
res = self.cursor.fetchall()
return res #提交
def execute(self,sql,args):
#提交语句可能会发生异常
try:
self.cursor.execute(sql,args)
except Exception as e:
print(e) def close(self):
self.cursor.close()
self.mysql.close()

整体代码部分

MySQL.py

import pymysql

class MySQL:

    #单例模式
__instance = None def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance def __init__(self):
self.mysql = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
database='orm_demo',
password='root',
charset='utf8',
autocommit=True
) #获取游标
self.cursor = self.mysql.cursor(
pymysql.cursors.DictCursor
) #查看
def select(self,sql,args=None):
#提交sql语句
self.cursor.execute(sql,args) #获取查询的结果
res = self.cursor.fetchall()
return res #提交
def execute(self,sql,args):
#提交语句可能会发生异常
try:
self.cursor.execute(sql,args)
except Exception as e:
print(e) def close(self):
self.cursor.close()
self.mysql.close()

orm.py

from MySQL import MySQL

# 定义字段类
class Field(object):
def __init__(self, name, column_type, primary_key, default):
self.name = name
self.column_type = column_type
self.primary_key = primary_key
self.default = default class StringField(Field):
def __init__(self,name,
column_type='varchar=(255)',
primary_key=False,
default=None):
super().__init__(name,column_type,primary_key,default) class IntegerField(Field):
def __init__(self,
name,
column_type='int',
primary_key=False,
default=None):
super().__init__(name, column_type, primary_key, default) class ModelMetaClass(type):
print("ModelMetaClass")
def __new__(cls,class_name,class_base,class_attrs):
print("ModelMetaClass_new")
#实例化对象的时候也会执行,我们要把这一次拦截掉
if class_name == 'Models':
#为了能让实例化顺利完成,返回一个空对象就行
return type.__new__(cls,class_name,class_base,class_attrs)
#获取表名
table_name = class_attrs.get('table_name',class_name) #定义一个存主键的的变量
primary_key = None #定义一个字典存储字段信息
mapping = {} #name='tid',primary_key=True
#for来找到主键字段
for k,v in class_attrs.items():
#判断信息是否是字段
if isinstance(v,Field):
mapping[k] = v
#寻找主键
if v.primary_key:
if primary_key:
raise TypeError("主键只有一个")
primary_key=v.name #将重复的键值对删除,因为已经放入了mapping
for k in mapping.keys():
class_attrs.pop(k)
if not primary_key:
raise TypeError("表必须要有一个主键")
class_attrs['table_name']=table_name
class_attrs['primary_key']=primary_key
class_attrs['mapping']=mapping
return type.__new__(cls,class_name,class_base,class_attrs) class Models(dict,metaclass=ModelMetaClass):
print("Models")
def __init__(self,**kwargs):
print(f'Models_init')
super().__init__(self,**kwargs) def __getattr__(self, item):
return self.get(item,"没有该值") def __setattr__(self, key, value):
self[key]=value #查找
@classmethod
def select(cls,**kwargs):
ms=MySQL() #如果没有参数默认是查询全部的
if not kwargs:
sql='select * from %s'%cls.table_name
res=ms.select(sql)
else:
k = list(kwargs.keys())[0]
v = kwargs.get(k)
sql='select * from %s where %s=?'%(cls.table_name,k) #防sql注入
sql=sql.replace('?','%s') res=ms.select(sql,v)
if res:
return [cls(**i) for i in res] #新增
def save(self):
ms=MySQL() #存字段名
fields=[]
#存值
values=[]
args=[] for k,v in self.mapping.items():
#主键自增,不用给他赋值
if not v.primary_key:
fields.append(v.name)
args.append("?")
values.append(getattr(self,v.name)) sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args))) sql = sql.replace('?','%s') ms.execute(sql,values) def update(self):
ms = MySQL()
fields = []
valuse = []
pr = None
for k,v in self.mapping.items():
#获取主键值
if v.primary_key:
pr = getattr(self,v.name,v.default)
else:
fields.append(v.name+'=?')
valuse.append(getattr(self,v.name,v.default))
print(fields,valuse)
sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr) sql = sql.replace('?',"%s") ms.execute(sql,valuse) class Teacher(Models):
print("teacher")
table_name='teacher'
tid = IntegerField(name='tid',primary_key=True)
tname = StringField(name='tname') if __name__ == '__main__':
# tea=Teacher(tname="haha")
tea2=Teacher(tname="haha",tid=5)
# print(Teacher.select(tid=1))
# Teacher.save(tea)
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. 使用Spring Data JPA进行数据分页与排序

    一.导读 如果一次性加载成千上万的列表数据,在网页上显示将十分的耗时,用户体验不好.所以处理较大数据查询结果展现的时候,分页查询是必不可少的.分页查询必然伴随着一定的排序规则,否则分页数据的状态很难控 ...

  2. 在windows主机中,利用XSHELL生成“密钥”进行虚拟机与物理机的传输

    首先你要有虚拟机,其次你要可以互相ping通(主机与虚拟机) 接着你要有xshell 软件  没有的话可以点击链接下载 Xshell  6  提取码:cj5t 打开Xshell软件  在工具栏中选择“ ...

  3. 证明:S = 1 + 1/2 + 1/4 + 1/8 + 1/16 + ·······,求证 S = 2

    证: S = 1 + 1/2 + 1/4 + 1/8 + 1/16 + ······· (式1) 将式1左右两边除以2,得: S/2 = 1/2 + 1/4 + 1/8 + 1/16 + 1/32 + ...

  4. 使用Typescript重构axios(三十二)——写在最后面(总结)

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  5. [校内自测 NOIP模拟题] chenzeyu97要请客(单调栈)

    题目描述 chenzeyu97的家可以看成是一个n*m的矩阵,每块区域都有独一无二的海拔高度h(h>0)!其最大值为n*m. 现在他要选择一个子矩阵摆放一张桌子,在他眼里,这样摆放桌子的美观度为 ...

  6. ElasticSearch(五):Mapping和常见字段类型

    ElasticSearch(五):Mapping和常见字段类型 学习课程链接<Elasticsearch核心技术与实战> 什么是Mapping Mapping类似数据库中的schema的定 ...

  7. 【原创】python倒排索引之查找包含某主题或单词的文件

    什么是倒排索引? 倒排索引(英语:Inverted index),也常被称为反向索引.置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射.它是文 ...

  8. python入门斐波那契数列之迭代,递归

    迭代 def fab(n): a1=1 a2=1 a3=1 if n < 1 : print("输入有误!") return -1 while n-2 > 0 : a3 ...

  9. 基于c/s架构的远程登陆服务的步骤。

    1:上/下位机安装相应的服务程序.(确保内核支持该服务)2:上位机(作为服务器端)配置能够给下位机访问目录的所在地,及其读写权限.3:在/dev目录下创建该服务其所需要使用的虚拟文件设备,同时按照该服 ...

  10. python 快速发送大量邮件

    因为公司需求,需要发送千万封级别邮件. # coding:utf-8 import csv import smtplib from email.mime.text import MIMEText im ...