手撸orm框架
一 前言
1 我在实例化一个user对象的时候,可以user=User(name='lqz',password='123')
2 也可以 user=User()
user['name']='lqz'
user['password']='123'
3 也可以 user=User()
user.name='lqz'
user.password='password'
前两种,可以通过继承字典dict来实现,第三种,用getattr和setattr
__getattr__ 拦截点号运算。当对未定义的属性名称和实例进行点号运算时,就会用属性名作为字符串调用这个方法。如果继承树可以找到该属性,则不调用此方法
__setattr__会拦截所有属性的的赋值语句。如果定义了这个方法,self.arrt = value 就会变成self,__setattr__("attr", value).这个需要注意。当在__setattr__方法内对属性进行赋值是,不可使用self.attr = value,因为他会再次调用self,__setattr__("attr", value),则会形成无穷递归循环,最后导致堆栈溢出异常。应该通过对属性字典做索引运算来赋值任何实例属性,也就是使用self.__dict__['name'] = value
二 定义Model基类
class Model(dict):
def __init__(self, **kw):
super(Model, self).__init__(**kw) def __getattr__(self, key):# .访问属性触发
try:
return self[key]
except KeyError:
raise AttributeError('没有属性:%s' % key) def __setattr__(self, key, value):
self[key] = value
三 定义Field
数据库中每一列数据,都有:列名,列的数据类型,是否是主键,默认值
class Field:
def __init__(self, name, column_type, primary_key, default_value):
self.name = name
self.column_type = column_type
self.primary_key = primary_key
self.default_value = default_value class StringField(Field):
def __init__(self, name, column_type='varchar(100)', primary_key=False, default_value=None):
super().__init__(name, column_type, primary_key, default_value) class IntegerField(Field):
def __init__(self, name, primary_key=False, default_value=0):
super().__init__(name, 'int', primary_key, default_value)
四 定义元类
数据库中的每个表,都有表名,每一列的列名,以及主键是哪一列
既然我要用数据库中的表,对应这一个程序中的类,那么我这个类也应该有这些类属性
但是不同的类这些类属性又不尽相同,所以我应该怎么做?在元类里拦截类的创建过程,然后把这些东西取出来,放到类里面
所以用到了元类
class ModelMetaclass(type):
def __new__(cls, name, bases,attrs):
if name=='Model':
return type.__new__(cls,name,bases,attrs)
table_name=attrs.get('table_name',None)
if not table:
table_name=name
primary_key=None
mappings=dict()
for k,v in attrs.items():
if isinstance(v,Field):#v 是不是Field的对象
mappings[k]=v
if v.primary_key:
#找到主键
if primary_key:
raise TypeError('主键重复:%s'%k)
primary_key=k for k in mappings.keys():
attrs.pop(k)
if not primary_key:
raise TypeError('没有主键')
attrs['table_name']=table_name
attrs['primary_key']=primary_key
attrs['mappings']=mappingsreturn type.__new__(cls,name,bases,attrs)
五 继续Model基类
Model类是所有要对应数据库表类的基类,所以,Model的元类应该是咱上面写的那个,而每个数据库表对应类的对象,都应该有查询,插入,保存,方法
所以:
class Model(dict, metaclass=ModelMetaclass):
def __init__(self, **kw):
super(Model, self).__init__(**kw) def __getattr__(self, key): # .访问属性触发
try:
return self[key]
except KeyError:
raise AttributeError('没有属性:%s' % key) def __setattr__(self, key, value):
self[key] = value @classmethod
def select_all(cls, **kwargs):
ms = mysql_singleton.Mysql().singleton()
if kwargs: # 当有参数传入的时候
key = list(kwargs.keys())[0]
value = kwargs[key]
sql = "select * from %s where %s=?" % (cls.table_name, key)
sql = sql.replace('?', '%s')
re = ms.select(sql, value)
else: # 当无参传入的时候查询所有
sql = "select * from %s" % cls.table_name
re = ms.select(sql)
return [cls(**r) for r in re] @classmethod
def select_one(cls, **kwargs):
# 此处只支持单一条件查询
key = list(kwargs.keys())[0]
value = kwargs[key]
ms = mysql_singleton.Mysql().singleton()
sql = "select * from %s where %s=?" % (cls.table_name, key) sql = sql.replace('?', '%s')
re = ms.select(sql, value)
if re:
return cls(**re[0])
else:
return None def save(self):
ms = mysql_singleton.Mysql().singleton()
fields = []
params = []
args = []
for k, v in self.mapping.items():
fields.append(v.name)
params.append('?')
args.append(getattr(self, k, v.default))
sql = "insert into %s (%s) values (%s)" % (self.table_name, ','.join(fields), ','.join(params))
sql = sql.replace('?', '%s')
ms.execute(sql, args) def update(self):
ms = mysql_singleton.Mysql().singleton()
fields = []
args = []
pr = None
for k, v in self.mapping.items():
if v.primary_key:
pr = getattr(self, k, v.default)
else:
fields.append(v.name + '=?')
args.append(getattr(self, k, v.default))
sql = "update %s set %s where %s = %s" % (
self.table_name, ', '.join(fields), self.primary_key, pr) sql = sql.replace('?', '%s')
print(sql)
ms.execute(sql, args)
六 基于pymsql的数据库操作类(单例)
from conf import setting
import pymysql class Mysql:
__instance = None
def __init__(self):
self.conn = pymysql.connect(host=setting.host,
user=setting.user,
password=setting.password,
database=setting.database,
charset=setting.charset,
autocommit=setting.autocommit)
self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def close_db(self):
self.conn.close() def select(self, sql, args=None):
self.cursor.execute(sql, args)
rs = self.cursor.fetchall()
return rs def execute(self, sql, args):
try:
self.cursor.execute(sql, args)
affected = self.cursor.rowcount
# self.conn.commit()
except BaseException as e:
print(e)
return affected @classmethod
def singleton(cls):
if not cls.__instance:
cls.__instance = cls()
return cls.__instance
七 数据库连接池版的数据库操作类
在此之前,要先学习数据库链接池:链接
db_pool.py
import pymysql
from conf import setting
from DBUtils.PooledDB import PooledDB POOL = PooledDB(
creator=pymysql, # 使用链接数据库的模块
maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
mincached=6, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached=5, # 链接池中最多闲置的链接,0和None不限制
maxshared=3,
# 链接池中最多共享的链接数量,0和None表示全部共享。
blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。
ping=0,
# ping MySQL服务端,检查是否服务可用。 host=setting.host,
port=setting.port,
user=setting.user,
password=setting.password,
database=setting.database,
charset=setting.charset,
autocommit=setting.autocommit
)
mysql_pool.py
import pymysql
from ormpool import db_pool
from threading import current_thread class MysqlPool:
def __init__(self):
self.conn = db_pool.POOL.connection()
# print(db_pool.POOL)
# print(current_thread().getName(), '拿到连接', self.conn)
# print(current_thread().getName(), '池子里目前有', db_pool.POOL._idle_cache, '\r\n')
self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor) def close_db(self):
self.cursor.close()
self.conn.close() def select(self, sql, args=None):
self.cursor.execute(sql, args)
rs = self.cursor.fetchall()
return rs def execute(self, sql, args): try:
self.cursor.execute(sql, args)
affected = self.cursor.rowcount
# self.conn.commit()
except BaseException as e:
print(e)
finally:
self.close_db()
return affected
setting.py
host = '127.0.0.1'
port = 3306
user = 'root'
password = '123456'
database = 'youku2'
charset = 'utf8'
autocommit = True
手撸orm框架的更多相关文章
- 手撸ORM浅谈ORM框架之基础篇
好奇害死猫 一直觉得ORM框架好用.功能强大集众多优点于一身,当然ORM并非完美无缺,任何事物优缺点并存!我曾一度认为以为使用了ORM框架根本不需要关注Sql语句如何执行的,更不用关心优化的问题!!! ...
- 手撸ORM浅谈ORM框架之Add篇
快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...
- 手撸ORM浅谈ORM框架之Update篇
快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...
- 手撸ORM浅谈ORM框架之Delete篇
快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...
- 手撸ORM浅谈ORM框架之Query篇
快速传送 手撸ORM浅谈ORM框架之基础篇 手撸ORM浅谈ORM框架之Add篇 手撸ORM浅谈ORM框架之Update篇 手撸ORM浅谈ORM框架之Delete篇 手撸ORM浅谈ORM框架之Query ...
- 康少带你手撸orm
orm 什么是orm? 对象关系映射: 一个类映射成一张数据库的表 类的对象映射成数据库中的一条条数据 对象点数据映射成数据库某条记录的某个值 优点:不会写sql语句的程序员也可以很6的操作sql语句 ...
- 使用wsgiref手撸web框架
模板 前言 要说到应用程序,就不得不提的就是cs架构和BS架构 所谓的cs架构就是client端和server端,就像我们的电脑上的qq,微信等应用程序 bs架构就是浏览器端和server端,我们不需 ...
- 纯手撸web框架
纯手撸web框架 一.Web应用的组成 接下来我们学习的目的是为了开发一个Web应用程序,而Web应用程序是基于B/S架构的,其中B指的是浏览器,负责向S端发送请求信息,而S端会根据接收到的请求信息返 ...
- 重学 Java 设计模式:实战中介者模式「按照Mybaits原理手写ORM框架,给JDBC方式操作数据库增加中介者场景」
作者:小傅哥 博客:https://bugstack.cn - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 同龄人的差距是从什么时候拉开的 同样的幼儿园.同样的小学.一样 ...
随机推荐
- Sql2008R2的一个补丁BUG-大家使用时请注意
我们都知道Sqlserver为了提高并发,允许乐观隔离级别(读提交快照,快照)以便读与写之间不阻塞.这里有一个在Sqlserver2008R2 SP2 的热补丁(CU11)下RCSI(读提交快照)隔离 ...
- android dev概念快速入门
apk: android将源代码依赖库等经过编译后打包分发的应用. 打包详细过程如下: android-studio安装 由于google被qiang,需要制定proxy,可以使用sock,同时安装完 ...
- BBR,附CentOS 6/7配置过程
最近这段时间BBR都比较火,前面有说如何在CAC的Debian-8-64bit安装BBR正确打开方式,现在说下,CentOS 6/7配置过程. 推荐理由:没配置BBR前,用SS看U2B的速度206K/ ...
- Sql server 账号被锁住:"the account is currently locked out. The system administrator can unlock it."的解决办法(转载)
今天遇到的问题比较有意思.首先是很久没有打开测试数据库了,今天打开,使用service程序测试的时候出现下面的错误提示:Message: System.Data.SqlClient.SqlExcept ...
- C# 泛型约束 xxx<T> Where T:约束(一)
泛型约束 代码举例 发现我们游戏的代码中,主程写了很多类似这样的代码: public static T CreateObject<T>(out int objectId) where T ...
- ansible 碎记录
https://www.zhukun.net/archives/8167 ansible -i new/hosts new -m authorized_key -a "user=root k ...
- Jenkins 角色 项目权限管理
插件名称: Role-based Authorization Strategy 新建 两用户 配置项目安全策略 在系统管理页面点击Manage and Assign Roles进入角色管理页面: 进 ...
- 自己写的开源MVC-easyMVC分享
简介 基本风格是按照spring mvc做的,在后期会加入一些新的特性,封装成易于自己项目使用的mvc框架. github地址: https://github.com/tangyanbo/easymv ...
- [工具]iperf测试带宽
之前被要求测试网卡带宽能力,发现了iperf这个工具,记录下来防止遗忘. iperf是个开源跨平台测试带宽工具,windows.linux.macOS--都支持,安装也挺方便. 1.安装 地址:htt ...
- Angular2学习笔记(1)——Hello World
1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之前主要使用的是jQuery,由于 ...