db_helper.py是数据库操作包,主要有两个函数,分别是read()数据库读操作函数和write()数据库写操作函数。这个包的代码是从小戴同学分享的博文改造过来的。

 #!/usr/bin/env python
# coding=utf-8 import psycopg2
from common import log_helper
from config import const # 初始化数据库参数
db_name = const.DB_NAME
db_host = const.DB_HOST
db_port = const.DB_PORT
db_user = const.DB_USER
db_pass = const.DB_PASS def read(sql):
"""
连接pg数据库并进行数据查询
如果连接失败,会把错误写入日志中,并返回false,如果sql执行失败,也会把错误写入日志中,并返回false
如果所有执行正常,则返回查询到的数据,这个数据是经过转换的,转成字典格式,方便模板调用,其中字典的key是数据表里的字段名
"""
try:
# 连接数据库
conn = psycopg2.connect(database=db_name, user=db_user, password=db_pass, host=db_host, port=db_port)
# 获取游标
cursor = conn.cursor()
except Exception as e:
print(e.args)
log_helper.error('连接数据库失败:' + str(e.args))
return False
try:
# 执行查询操作
cursor.execute(sql)
# 将返回的结果转换成字典格式
data = [dict((cursor.description[i][0], value) for i, value in enumerate(row)) for row in cursor.fetchall()]
except Exception as e:
print(e.args)
log_helper.error('sql执行失败:' + str(e.args) + ' sql:' + str(sql))
return False
finally:
# 关闭游标和数据库链接
cursor.close()
conn.close()
# 返回结果(字典格式)
return data def write(sql, vars):
"""
连接pg数据库并进行写的操作
如果连接失败,会把错误写入日志中,并返回false,如果sql执行失败,也会把错误写入日志中,并返回false,如果所有执行正常,则返回true
"""
try:
# 连接数据库
conn = psycopg2.connect(database=db_name, user=db_user, password=db_pass, host=db_host, port=db_port)
# 获取游标
cursor = conn.cursor()
except Exception as e:
print(e.args)
log_helper.error('连接数据库失败:' + str(e.args))
return False
try:
# 执行sql语句
cursor.execute(sql, vars)
# 提交事务
conn.commit()
except Exception as e:
print(e.args)
# 如果出错,则事务回滚
conn.rollback()
log_helper.error('sql执行失败:' + str(e.args) + ' sql:' + str(sql))
return False
else:
# 获取数据
try:
data = [dict((cursor.description[i][0], value) for i, value in enumerate(row))
for row in cursor.fetchall()]
except Exception as e:
# 没有设置returning或执行修改或删除语句时,记录不存在
data = None
finally:
# 关闭游标和数据库链接
cursor.close()
conn.close() # 如果写入数据后,将数据库返回的数据返回给调用者
return data

  read(sql)是用来执行数据库查询操作,里面没有事务提交,所以用它来执行增删改操作时,虽然能提交成功,但执行后数据库记录也不会有什么变化,所以只能用它来执行select语句

  write(sql, data)是用来执行数据库写操作的,write函数执行后会返回下面几种状态:

  1.False状态(数据库链接失败、sql语句不正确、链接数据库操时等执行数据库出现异常时返回这个状态)

  2.None状态(sql语句没有添加RETURNING id代码指定sql语句执行结束后返回指定字段值时出现;你如果修改代码第80行,data = None为data = True,执行成功时则会返回True状态)

  3.[] (sql语句添加了returning函数,且执行修改或删除时,记录不存在)

  4.{'id': 1,}(sql语句添加了returning函数,执行成功后返回我们指定的字段值)

  PS:我们在执行新增的时候,如果想要获取新增的id,postgresql有一个非常好用的函数returning,只需要在增删改语句的后面添加returning id或returning id,name或returning *等你想要返回的字段名称,语句执行成功以后都会返回这些指定的字段值,大家可以尝试修改测试用例代码,看看返回的值是什么。

#!/usr/bin/evn python
# coding=utf-8 import unittest
from common import db_helper class DbHelperTest(unittest.TestCase):
"""数据库操作包测试类""" def setUp(self):
"""初始化测试环境"""
print('------ini------') def tearDown(self):
"""清理测试环境"""
print('------clear------') def test(self):
# 新增记录,不带return参数
sql = """
INSERT INTO product_class(
name, is_enable)
VALUES (%s, %s)
"""
data = ('糖果', 1)
result = db_helper.write(sql, data)
print(result) # 新增记录,使用return参数返回新增id
sql = """
INSERT INTO product_class(
name, is_enable)
VALUES (%s, %s)
RETURNING id;
"""
data = ('饼干', 1)
result = db_helper.write(sql, data)
print(result) # 修改不存在的记录
sql = """
UPDATE product_class
SET name=%s, is_enable=%s
WHERE id=10000
RETURNING id;
"""
data = ('糖果', 1)
result = db_helper.write(sql, data)
print(result) # 查询记录
sql = """
SELECT * FROM product_class
"""
result = db_helper.read(sql)
print(result) if __name__ == '__main__':
unittest.main()

  执行结果

------ini------
None
[{'id': 2}]
[]
[{'id': 1, 'name': '糖果', 'add_time': datetime.datetime(2017, 10, 16, 14, 51, 49), 'is_enable': 1}, {'id': 2, 'name': '饼干', 'add_time': datetime.datetime(2017, 10, 16, 15, 30, 50), 'is_enable': 1}]
------clear------

  

  encrypt_helper.py是加密操作包,目前只有md5加密函数,其他加密函数以后有需要再添加进来

#!/usr/bin/evn python
# coding=utf-8 import hashlib def md5(text):
"""md5加密函数"""
md5 = hashlib.md5()
if not isinstance(text, bytes):
text = str(text).encode('utf-8')
md5.update(text)
return md5.hexdigest()

  md5()参数类型支持各种类型,如果参数为非bytes类型时会自动转换为str类型来进行操作,例如以下测试用例,大家也可以尝试用元组、字典或列表类型测试看看结果

#!/usr/bin/evn python
# coding=utf-8 import unittest
from common import encrypt_helper class DbHelperTest(unittest.TestCase):
"""数据库操作包测试类""" def setUp(self):
"""初始化测试环境"""
print('------ini------') def tearDown(self):
"""清理测试环境"""
print('------clear------') def test(self):
result = encrypt_helper.md5(1)
print(result)
self.assertEqual(result, 'c4ca4238a0b923820dcc509a6f75849b') result = encrypt_helper.md5('')
print(result)
self.assertEqual(result, 'c4ca4238a0b923820dcc509a6f75849b') result = encrypt_helper.md5(b'')
print(result)
self.assertEqual(result, 'c4ca4238a0b923820dcc509a6f75849b') if __name__ == '__main__':
unittest.main()

  执行结果

------ini------
c4ca4238a0b923820dcc509a6f75849b
c4ca4238a0b923820dcc509a6f75849b
c4ca4238a0b923820dcc509a6f75849b
------clear------

  except_helper.py包主要功能是获取代码当前位置的堆栈信息,它被log_helper.py包的error()错误日志记录函数调用,输出发生错误时的堆栈信息内容,方便开发人员分析代码异常。

#!/usr/bin/evn python
# coding=utf-8 import os
import sys def detailtrace():
"""获取程序当前运行的堆栈信息"""
retStr = ""
f = sys._getframe()
f = f.f_back # first frame is detailtrace, ignore it
while hasattr(f, "f_code"):
co = f.f_code
retStr = "%s(%s:%s)->"%(os.path.basename(co.co_filename),
co.co_name,
f.f_lineno) + retStr
f = f.f_back
return retStr

  json_helper.py包里只有一个日期格式化类。

#!/usr/bin/evn python
# coding=utf-8 import json
import datetime class CJsonEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime.datetime):
return obj.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(obj, datetime.date):
return obj.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, obj)

  python的json将时间类型转换为字符串时,它会处理不了出现异常,需要使用这个自定义类进行格式化处理

  比如我们如果直接这样对时间类型进行转换时,就会出现异常:

    def test(self):
js = {
'test5': datetime.datetime.now(),
}
print(js)
result = json.dumps(js)
print(result)

  执行结果:

------ini------
{'test5': datetime.datetime(2017, 10, 16, 16, 56, 58, 654832)}
------clear------ Error
Traceback (most recent call last):
File "E:\Python\simple\code\test\json_helper_test.py", line 26, in test
result = json.dumps(js)
File "C:\Users\Empty\AppData\Local\Programs\Python\Python35-32\lib\json\__init__.py", line 230, in dumps
return _default_encoder.encode(obj)
File "C:\Users\Empty\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 198, in encode
chunks = self.iterencode(o, _one_shot=True)
File "C:\Users\Empty\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 256, in iterencode
return _iterencode(o, 0)
File "C:\Users\Empty\AppData\Local\Programs\Python\Python35-32\lib\json\encoder.py", line 179, in default
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: datetime.datetime(2017, 10, 16, 16, 56, 58, 654832) is not JSON serializable

  改成下面代码的话就正常了

    def test(self):
js = {
'test5': datetime.datetime.now(),
}
print(js)
result = json.dumps(js, cls=json_helper.CJsonEncoder)
print(result)

  执行结果

------ini------
{'test5': datetime.datetime(2017, 10, 16, 16, 59, 40, 756103)}
{"test5": "2017-10-16 16:59:40"}
------clear------

  本文对应的源码下载

版权声明:本文原创发表于 博客园,作者为 AllEmpty 本文欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。

python开发QQ群:669058475(本群已满)、733466321(可以加2群)    作者博客:http://www.cnblogs.com/EmptyFS/

我的第一个python web开发框架(11)——工具函数包说明(二)的更多相关文章

  1. 我的第一个python web开发框架(41)——总结

    我的第一个python web开发框架系列博文从17年6.7月份开始写(存了近十章稿留到9月份才开始发布),到今天结束,一年多时间,想想真不容易啊. 整个过程断断续续,中间有段时间由于工作繁忙停了好长 ...

  2. 我的第一个python web开发框架(14)——后台管理系统登录功能

    接下来正式进入网站的功能开发.要完成后台管理系统登录功能,通过查看登录页面,我们可以了解到,我们需要编写验证码图片获取接口和登录处理接口,然后在登录页面的HTML上编写AJAX. 在进行接口开发之前, ...

  3. 我的第一个python web开发框架(10)——工具函数包说明(一)

    PS:原先是想直接进入功能开发,要用到什么函数时再创建,这样也容易熟悉每个函数的由来和使用方法,但考虑到这样操作,到时会经常在不同文件间切换,不好描述,容易造成混乱,所以还是使用函数库这种方式来说明. ...

  4. 我的第一个python web开发框架(5)——开发前准备工作(了解编码前需要知道的一些常识)

    中午吃饭时间到了,小白赶紧向老菜坐的位置走过去. 小白:老大,中午请你吃饭. 老菜:哈哈...又遇到问题了吧,这次得狠狠宰你一顿才行. 小白:行行行,只要您赏脸,米饭任吃,嘻嘻,我们边走边聊. ... ...

  5. 我的第一个python web开发框架(1)——前言

    由于之前经验不是很丰富,写的C#系统太过复杂,所以一直想重写,但学的越多越觉得自己懂的越少,越觉的底气不足.所以一直不敢动手,在内心深处对自己讲,要静下心来认真学习,继续沉淀沉淀.这两年多以来找各种机 ...

  6. 我的第一个python web开发框架(3)——怎么开始?

    小白与小美公司经过几次接触商谈,好不容易将外包签订了下来,准备开始大干一场.不过小白由于没有太多的项目经验,学过python懂得python的基本语法,在公司跟着大家做过简单功能,另外还会一些HTML ...

  7. 我的第一个python web开发框架(22)——一个安全小事故

    在周末的一个早上,小白还在做着美梦,就收到了小美的连环追魂call,电话一直响个不停. 小白打着哈欠拿起电话:早上好美女. 小美:出事了出事了,我们公司网站一早访问是一片空白,什么内容都没有了,你赶急 ...

  8. 我的第一个python web开发框架(8)——项目结构与RESTful接口风格说明

    PS:再次说明一下,原本不想写的太啰嗦的,可之前那个系列发布后发现,好多朋友都想马上拿到代码立即能上手开发自己的项目,对代码结构.基础常识.分类目录与文件功能结构.常用函数......等等什么都不懂, ...

  9. 我的第一个python web开发框架(9)——目录与配置说明

    和老大聊完后,小白回家接收到相关工具函数包后,就按要求开始干活,首先要做的是熟悉配置参数和了解工具函数有哪些实用的工具. 由于这个项目比较简单,所以不用创建那么多分类,只需要api.common.co ...

  10. 我的第一个python web开发框架(17)——产品管理

    这是后台管理系统最后一个功能,产品管理,它的接口与页面功能与上一章差不多. 获取产品列表接口 @get('/api/product/') def callback(): ""&qu ...

随机推荐

  1. Python[小甲鱼003小插曲之变量和字符串]

      >>>teacher = 3 >>>teacher  3 #在定义了一个变量后可以之间输入整个变量即可访问这个变量.   >>> teache ...

  2. Java 第十一周总结

    1. 本周学习总结 2. 书面作业 1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchronized修饰方法实现互斥同步访问,还有什么办法实现互斥同步访 ...

  3. 201521123113《Java程序设计》第13周学习总结

    1. 本周学习总结 2. 书面作业 Q1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 返回的结果 ...

  4. Memcached-高性能的分布式内存缓存服务器

    Memcached是高性能的分布式内存缓存服务器,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像.视频.文件以及数据库检索的结果等, 由国外社区网站 LiveJou ...

  5. 升级与修改Nginx

    自从上次安装了Nginx后,学到了很多新的东西,比如http2.0... 而且还发现nginx还出了新版本,遂决定升级下,还是那个URL,下载最新版. ./configure --user=www - ...

  6. bzoj 3212 Pku3468 A Simple Problem with Integers

    3212: Pku3468 A Simple Problem with Integers Time Limit: 1 Sec  Memory Limit: 128 MB Description You ...

  7. 杂谈--DML触发器学习

    触发器按类型分为三类: 1. DML 触发器,在数据变更时触发: 2. DDL 触发器,在修改数据库级别或实例级别对象时触发: 3. Login 触发器,在用户登录时触发: 最常见的是DML触发器,D ...

  8. Python数据分析(二): Numpy技巧 (3/4)

    numpy.pandas.matplotlib(+seaborn)是python数据分析/机器学习的基本工具. numpy的内容特别丰富,我这里只能介绍一下比较常见的方法和属性.   昨天晚上发了第一 ...

  9. Distribute Candies

    Given an integer array with even length, where different numbers in this array represent different k ...

  10. 渣渣学QT

    初学QT,自己的一些小总结,错误之处,望大神指点一二: 1,添加资源文件时想应用在界面的背景,但是发现用不了,后来才知道是没有"构建"?应该是要在构建之后才将所添加的资源文件真正的 ...