手撸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 - 原创系列专题文章 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 同龄人的差距是从什么时候拉开的 同样的幼儿园.同样的小学.一样 ...
随机推荐
- Supervisor 管理进程,Cloud Insight 监控进程,完美!
Supervisor 是由 Python 语言编写.基于 linux 操作系统的一款服务器管理工具,用于监控服务器的运行,发现问题能立即自动预警及自动重启等. Cloud Insight 是一款次世代 ...
- [经典bug]弹框关闭按钮点击后程序闪退
问题背景: 业务上遇到一个很诡异的问题:弹框界面上有一个关闭按钮,切换后台再返回后,点击关闭按钮,部分机型上会直接崩溃.点击手机返回键关闭界面则正常. 问题原因: 点击关闭按钮的操作属于UI线程,直接 ...
- 有关java编辑器myeclipse编辑网站的一些设置(个人习惯)
一.界面显示设置 首先进入一个新的空间,里面的设置肯定都是默认的.点击上方导航栏的window-Perferences-Appearance可以去进行设置界面的显示,Theme中可以选择windows ...
- October 29th, 2017 Week 44th Sunday
There was another life that I might have had, but I am having this one. 我明明可以过另一种生活,但我却选择了这一种. Be re ...
- 自定义上传控件(兼容IE8)
上传控件是 <input type="file"/> 而实际开发过程中,都会自定义一个控件,因为这个控件本身难看,而且不同浏览器效果不一样. 如IE8显示如下: 谷歌浏 ...
- File API
ES5 推出了一系列的 API: BLOB (二进制大对象) File (文件接口,基于 BLOB,但是增加了文件相关的方法,比如路径,大小) FileList (借助 <input type= ...
- 4.Dubbo2.5.3集群容错和负载均衡
转载请出自出处:http://www.cnblogs.com/hd3013779515/ 1.集群容错和负载均衡原理 各节点关系: 这里的Invoker是Provider的一个可调用Service的抽 ...
- HTML标签之marquee
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/zkn_CS_DN_2013/article/details/25229719 <html> ...
- 死磕nginx系列--使用upsync模块实现负载均衡
问题描述 nginx reload是有一定损耗的,如果你使用的是长连接的话,那么当reload nginx时长连接所有的worker进程会进行优雅退出,并当该worker进程上的所有连接都释放时,进程 ...
- nmap数据流
扫描者:1.1.1.1被扫描者:2.2.2.2 0x00 介绍 在日常工作对目标信息收集时,我们经常用到nmap这款网络探测工具和安全/端口扫描器,虽然我们关注的是结果(如目标开启了哪些危险端口,什么 ...