一、原因

最近在使用python3和sqlite3编辑一些小程序,由于要使用数据库,就离不开增、删、改、查,sqlite3的操作同java里的jdbc很像,于是就想找现成的操作类,找来找去,发现一个相对来说简单的封装,代码如下:

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u013314786/article/details/78226902
————————————————
import sqlite3 class EasySqlite:
"""
sqlite数据库操作工具类
database: 数据库文件地址,例如:db/mydb.db
"""
_connection = None def __init__(self, database):
# 连接数据库
self._connection = sqlite3.connect(database) def _dict_factory(self, cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d def execute(self, sql, args=[], result_dict=True, commit=True)->list:
"""
执行数据库操作的通用方法
Args:
sql: sql语句
args: sql参数
result_dict: 操作结果是否用dict格式返回
commit: 是否提交事务
Returns:
list 列表,例如:
[{'id': 1, 'name': '张三'}, {'id': 2, 'name': '李四'}]
"""
if result_dict:
self._connection.row_factory = self._dict_factory
else:
self._connection.row_factory = None
# 获取游标
_cursor = self._connection.cursor()
# 执行SQL获取结果
_cursor.execute(sql, args)
if commit:
self._connection.commit()
data = _cursor.fetchall()
_cursor.close()
return data if __name__ == '__main__':
db = EasySqlite('browser.db')
# print(db.execute("select name from sqlite_master where type=?", ['table']))
# print(db.execute("pragma table_info([user])"))
# print(execute("insert into user(id, name, password) values (?, ?, ?)", [2, "李四", "123456"]))
print(db.execute("select id, name userName, password pwd from user"))
print(db.execute("select * from user", result_dict=False))
print(db.execute("select * from user"))
    db = EasySqlite('browser.db')
# print(db.execute("select name from sqlite_master where type=?", ['table']))
# print(db.execute("pragma table_info([user])"))
# print(execute("insert into user(id, name, password) values (?, ?, ?)", [2, "李四", "123456"]))
#print(db.execute("select id, name userName, password pwd from user"))
#print(db.execute("select * from user", result_dict=False))
#print(db.execute("select * from user"))

执行的方式如上一段代码,大体上是初始化时传入sqlite3数据库路径,使用db.excecute方法来执行sql,返回的是Dict数组。


二、此工具类的扩展

但一个类写相同的增、删、改、查,感觉很费时间,于是想借鉴java的反射机制,尝试使用python的反射来实现MVC中的module基类,得到以下代码:

class DbSuper(object):
dbHelper=None #类变量,共用一个EasySqlite工具类 def __init__(self):
"""
初始化数据库 """
super().__init__() def setDb(self, dburl):
"""
参数:
dburl——数据库文件位置,str类型
"""
DbSuper.dbHelper = EasySqlite(dburl) def add(self, obj):
"""
将实例储存到数据库,数据库中的表名应与类名一致,表中字段名与类定义的变量名一致 ,顺序也得一致
参数:
obj——类实例
返回值:无
"""
sql = 'insert into '+type(obj).__name__+' values(' #通过type(obj).__name__获得表名
paras = [] #sql语句的参数
tag = True
for attr in obj.__dict__.keys(): #获取实例对象的属性名obj.__dict__
if tag:
tag=False #第一项是ID,自动生成,跳过
continue
sql += ',?' #循环几次,就加几次? 生成 insert into xxxx values(,?,?,?,?)的sql语句
para = getattr(obj, attr) # 使用getattr函数,利用反射获得类属性实际的值 if type(para)==str: #对值进行判断,如果非str类型,应做转换,避免sql执行错误
paras.append(para)
else :
paras.append(str(para))
sql = sql.replace(',','null,', 1) #将多余的 , 处理一下
sql += ')'
#print(sql)
#print(paras)
DbSuper.dbHelper.execute(sql, paras) #利用工具类执行SQL def findByProperty(self, objclass, propertyName, propertyValueStr,strict = True, orderby='id', pager = False, numPerPage=1, page = 1):
"""
通过类的某一个属性查找
参数:
objclass——class类型,类名
propertyName——str类型,筛选依据的属性名
propertyValueStr——object类型,筛选依据的属性名对应的值
strict——bool类型,文本字段是否精确匹配,非文本字段请勿改变此值
orderby——str类型,排序的依据,默认ID排序
pager——bool类型,查询的结果是否分页
numPerPage——int类型,如pager=True,则此参数起作用,每页显示数据量
page——int类型,如pager=True,则此参数起作用,页数
返回值:objclass的list
"""
sql = 'select * from %s where ' % objclass.__name__
#对propertyValueStr进行判断,非str型,进行转换
if type(propertyValueStr) != str:
propertyValueStr = str(propertyValueStr) if strict:#默认严格匹配
sql += '%s = ? order by %s '% (propertyName, orderby)
else:
sql += '%s like ? order by %s '% (propertyName, orderby)
propertyValueStr = '%' + propertyValueStr + '%'
if pager: #对pager进行判断,默认不进行分页处理
sql += 'limit %d offset %d' % (numPerPage, numPerPage * (page - 1))
retObjects = [] #DbSuper.dbHelper.execute(sql, [propertyValueStr, ])执行SQL,结果返回为Dict数组
print(sql)
for ret in DbSuper.dbHelper.execute(sql, [propertyValueStr, ]):
#利用变量生成实例
obj = objclass()
#调用initByStr方法,将Dict解释,并赋值给对应属性,因不同类实现方式不同,故此方法由类声明时自行完成,类似接口
obj.initByStr(ret)
retObjects.append(obj)
return retObjects def findByPropertyFirst(self, objclass, propertyName, propertyValueStr, strict=True):
"""
类似于findByProperty,做了一定简化,且只查询一个结果
返回值:成功返回对象实例,失败返回空
"""
sql = 'select * from %s where %s = ? limit 1' % (objclass.__name__, propertyName)
if strict==False:
propertyValueStr = '%' + propertyValueStr + '%'
ret = DbSuper.dbHelper.execute(sql, [propertyValueStr, ])
if len(ret)>0:
obj = objclass()
obj.initByStr(ret[0])
return obj
else:
return None def modify(self, obj, propertyIndex='id'):
"""
更新类,并存于数据库
参数:
obj——类实例
propertyIndex——筛选依据的字段,默认ID
返回值: 无
"""
sql = 'update %s set ' % type(obj).__name__ #利用反射,通过实例获得类名,即表名
params = []
for attr in obj.__dict__.keys(): #遍历每个属性,生成update语句中的set xxx=?,注意要跳过筛选依据的属性
if attr == propertyIndex:
continue
else:
sql += ', %s=?' % attr #对属性值进行处理,如果不是str型,要转换
if type(getattr(obj, attr)) == str:
params.append(getattr(obj, attr))
else:
params.append(str(getattr(obj, attr)))
#筛选条件语句生成
sql += ' where %s = ?' % propertyIndex
#加入参数
params.append(getattr(obj, propertyIndex))
#对生成的sql语句处理,去掉多余的, 执行SQL语句
DbSuper.dbHelper.execute(sql .replace(',', '', 1), params) def delete(self, obj, propertyIndex='id'):
"""
删除对象
参数:
obj——待删除的对象
propertyIndex——筛选依据 """
sql = 'delete from %s where %s=?' % (type(obj).__name__, propertyIndex)
param = getattr(obj, propertyIndex)
if type(param) != str:
param = str(param)
DbSuper.dbHelper.execute(sql , [param, ])

三、使用前提条件

  • 类名要与数据库中表名一致
  • 类中属性与数据库中字段名一致
  • 为解决查询结果转换成类的问题,类中要实现一个方法initByStr

四、使用举例

1.数据库中表创建示例,注意表名operators,此处模拟一用户基本信息

CREATE TABLE [operators] (
[id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[loginname] vaRCHAR(20) UNIQUE NOT NULL,
[loginpass] vaRCHAR(100) NOT NULL,
[showname] vaRCHAR(30) NULL,
[level] vaRCHAR(100) NULL
)

2.类operators声明


# -*- coding=utf-8 -*-
from enum import Enum
import abc

class Levels(Enum):
"""
枚举类,标明权限类型
"""
DATA_INPUTER='查询数据,录入数据,修改数据'
USER_MANAGER='增加用户,修改用户基本信息'
POWER_MANAGER='增加用户,修改用户基本信息,修改用户权限' class DbEntity(object): @abc.abstractmethod
def initByStr(self, attrDict):
pass class Operators(DbEntity):
"""
用户类
"""
def __init__(self):
super().__init__()
self.id=0
self.loginName=''
self.loginPass=''
self.showName=''
self.level=Levels.DATA_INPUTER def initByStr(self, attrDict):
if len(attrDict)==5:
self.id = int(attrDict['id'])
self.loginName = attrDict['loginname']
self.loginPass = attrDict['loginpass']
self.showName = attrDict['showname']
self.level = Levels(attrDict['level'])
DbEntity是基类,只声明了一个接口initByStr,子类必须实现,原本我想在扩展类里实现这个方法,但也只能实现基本数据类型,一旦类里的属性比较复杂也不好实现,所以还是由类中声明每一个字符串如何转化成类。
3.准备工作完成后,下面实现OperatorDao,代码如下:
class OperatorDao(DbSuper):

    def __init__(self):
super().__init__() def findById(self, id):
"""
根据ID查找类
返回类,如未找到返回空
"""
return super().findByPropertyFirst(Operators, 'id', id) def findByLoginname(self, loginname):
"""
根据登录名查找类
返回类,如未找到返回空
"""
return super().findByPropertyFirst(Operators, 'loginName', loginname)
#return super().findByProperty(Operators, 'loginName', loginname)
#return super().findByProperty(Operators, 'loginName', loginname,strict=False)
#return super().findByProperty(Operators, 'loginName', loginname, pager = True, numPerPage=5, page = 1) def addOper(self, oper):
#可以对实例进一步处理,比如MD5加密 oper.loginPass = MDUtils.md5Text(oper.loginPass)
return super().add(oper) def modiOper(self, oper):
return super().modify(oper) def delOper(self, oper):
return super().delete(oper) if __name__ == '__main__':
operatorDao = OperatorDao()
operatorDao.setDb('xxxxxx.s3db')
oper = operatorDao.findByLoginname('test')
for op in oper:
print(op)

只是简单扩展,还可以加入配置文件,标出类属性与数据库字段关系,这样就可以不用字段名与类属性一致,但实现更复杂,目前先做到这个程度,有时间再进一步处理。

python sqlite3操作类扩展,包含数据库分页的更多相关文章

  1. ACCESS数据库C#操作类(包含事务)

    转自http://blog.csdn.net/allen3010/article/details/6336717 这个是针对ACCESS数据库操作的类,同样也是从SQLHELPER提取而来,分页程序的 ...

  2. Python sqlite3操作笔记

    创建数据库 def create_tables(dbname): conn = sqlite3.connect(dbname) print "Opened database successf ...

  3. APPIUM API整理(python)---操作类

    前言:android手机大家都很熟悉,操作有按键.触摸.点击.滑动等,各种操作方法可以通过api的方法来实现. 参考博文:http://blog.csdn.net/bear_w/article/det ...

  4. 一个数据库操作类,适用于Oracle,ACCESS,SQLSERVER

    最近做了一个数据诊断的项目,里面自己写了一个数据库的操作类,包含:连接数据库.读数据表.执行SQL操作,释放数据库等组成,希望对大家有用,由于水平有限,若有错误或者代码不足地方欢迎指正,谢谢. ADO ...

  5. C#对XML操作类

    C#对XML操作类 该类包含了对XML文件的创建,添加,读取,删除,修改等操作 //#define isUnity #if isUnity using UnityEngine; #endif usin ...

  6. python sqlite3 数据库操作

    python sqlite3 数据库操作 SQLite3是python的内置模块,是一款非常小巧的嵌入式开源数据库软件. 1. 导入Python SQLite数据库模块 import sqlite3 ...

  7. [python][django学习篇][5]选择数据库版本(默认SQLite3) 与操作数据库

    推荐学习博客:http://zmrenwu.com/post/6/ 选择数据库版本(SQLite3) 如果想选择MySQL等版本数据库,请先安装MySQL并且安装python mysql驱动,这里不做 ...

  8. python 数据库操作类

    #安装PyMySQL:pip3 install PyMySQL   #!/usr/bin/python3   #coding=utf-8   #数据库操作类     from  datetime  i ...

  9. PHP 数据库操作类:ezSQL

    EZSQL类介绍: 下载地址:http://www.jb51.net/codes/26393.htmlezsql是一个小型的快速的数据库操作类,可以让你很容易地用PHP操作各种数据库( MySQL.o ...

随机推荐

  1. HDU-1251-统计难题(Trie树)(BST)(AVL)

    字典树解法(Trie树) Accepted 1251 156MS 45400K 949 B C++ #include"iostream" #include"cstdlib ...

  2. Java的简易ATM系统

    大纲   ATM 机系统                   1.注册(账户(系统随机生成 15 位) - 密码(6位) - 余额)                   2.登录            ...

  3. idea 集成svn

    1.下载svn客户端 官网下载地址:https://tortoisesvn.net/downloads.html 2. 安装svn客户端 在安装svn客户端的时候一定要勾选,否则在idea上集成svn ...

  4. 基于hibernate的BaseDao及其实现类的设计

    以前做设计的时候dao接口和它的实现了,这样子就不必写这么多的重复代码了.但由于对反射没有了解,除非依赖hibernate的其他组件,否则写不出来.不过,有了反射,我们可以通过泛型来实现我们想要做的功 ...

  5. python3爬虫:利用urllib与有道翻译获得翻译结果

    在实现这一功能时遇到了一些困难,由于按照<零基础入门python>中的代码无法实现翻译,会爆出“您的请求来源非法,商业用途使用请关注有道翻译API官方网站“有道智云”: http://ai ...

  6. unique()函数使用

    前提:要先令容器有序. unique的作用是“去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址. 用法:uni ...

  7. 仿射密码Python实现

    算法分析 仿射密码结合了移位密码和乘数密码的特点,是移位密码和乘数密码的组合. 仿射密码的加密算法就是一个线性变化,即对明文字符x,对应的密文字符为y=ax+b(mod26)其中,a, b属于Z26且 ...

  8. IOS常见语法解惑

    由于工作过程中经常需要查看IOS的Objective-C代码,遂把一些常见的.有疑问的OC语法列出,方便之后会看,提升效率. Objective-C中的@语法 @interface告诉编译器,我要声明 ...

  9. RxJava学习笔记(操作符)

    前言 上一篇文章介绍了RxJava的基础知识和简单实现,篇幅已经比较多了,所以把操作符(Operators)相关的内容放在这一篇.有了上一篇文章的基础,相信会比较容易理解操作符相关的内容了. 操作符( ...

  10. 安卓权威编程指南 -笔记(19章 使用SoundPool播放音频)

    针对BeatBox应用,可以使用SoundPool这个特别定制的实用工具. SoundPool能加载一批声音资源到内存中,并支持同时播放多个音频文件.因此所以,就算用户兴奋起来,狂按按钮播放全部音频, ...