我的第一個python web開發架構(11)——工具函數包說明(二),pythonweb
db_helper.py是資料庫操作包,主要有兩個函數,分別是read()資料庫讀操作函數和write()資料庫寫操作函數。這個包的代碼是從小戴同學分享的博文改造過來的。
1 #!/usr/bin/env python 2 # coding=utf-8 3 4 import psycopg2 5 from common import log_helper 6 from config import const 7 8 # 初始化資料庫參數 9 db_name = const.DB_NAME10 db_host = const.DB_HOST11 db_port = const.DB_PORT12 db_user = const.DB_USER13 db_pass = const.DB_PASS14 15 16 def read(sql):17 """18 串連pg資料庫並進行資料查詢19 如果串連失敗,會把錯誤寫入日誌中,並返回false,如果sql執行失敗,也會把錯誤寫入日誌中,並返回false20 如果所有執行正常,則返回查詢到的資料,這個資料是經過轉換的,轉成字典格式,方便模板調用,其中字典的key是資料表裡的欄位名21 """22 try:23 # 串連資料庫24 conn = psycopg2.connect(database=db_name, user=db_user, password=db_pass, host=db_host, port=db_port)25 # 擷取遊標26 cursor = conn.cursor()27 except Exception as e:28 print(e.args)29 log_helper.error('串連資料庫失敗:' + str(e.args))30 return False31 try:32 # 執行查詢操作33 cursor.execute(sql)34 # 將返回的結果轉換成字典格式35 data = [dict((cursor.description[i][0], value) for i, value in enumerate(row)) for row in cursor.fetchall()]36 except Exception as e:37 print(e.args)38 log_helper.error('sql執行失敗:' + str(e.args) + ' sql:' + str(sql))39 return False40 finally:41 # 關閉遊標和資料庫連結42 cursor.close()43 conn.close()44 # 返回結果(字典格式)45 return data46 47 48 def write(sql, vars):49 """50 串連pg資料庫並進行寫的操作51 如果串連失敗,會把錯誤寫入日誌中,並返回false,如果sql執行失敗,也會把錯誤寫入日誌中,並返回false,如果所有執行正常,則返回true52 """53 try:54 # 串連資料庫55 conn = psycopg2.connect(database=db_name, user=db_user, password=db_pass, host=db_host, port=db_port)56 # 擷取遊標57 cursor = conn.cursor()58 except Exception as e:59 print(e.args)60 log_helper.error('串連資料庫失敗:' + str(e.args))61 return False62 try:63 # 執行sql語句64 cursor.execute(sql, vars)65 # 提交事務66 conn.commit()67 except Exception as e:68 print(e.args)69 # 如果出錯,則交易回復70 conn.rollback()71 log_helper.error('sql執行失敗:' + str(e.args) + ' sql:' + str(sql))72 return False73 else:74 # 擷取資料75 try:76 data = [dict((cursor.description[i][0], value) for i, value in enumerate(row))77 for row in cursor.fetchall()]78 except Exception as e:79 # 沒有設定returning或執行修改或刪除語句時,記錄不存在80 data = None81 finally:82 # 關閉遊標和資料庫連結83 cursor.close()84 conn.close()85 86 # 如果寫入資料後,將資料庫返回的資料返回給調用者87 return dataView Code
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-8import unittestfrom common import db_helperclass 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-8import hashlibdef 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-8import unittestfrom common import encrypt_helperclass 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('1') print(result) self.assertEqual(result, 'c4ca4238a0b923820dcc509a6f75849b') result = encrypt_helper.md5(b'1') print(result) self.assertEqual(result, 'c4ca4238a0b923820dcc509a6f75849b')if __name__ == '__main__': unittest.main()
執行結果
------ini------c4ca4238a0b923820dcc509a6f75849bc4ca4238a0b923820dcc509a6f75849bc4ca4238a0b923820dcc509a6f75849b------clear------
except_helper.py包主要功能是擷取代碼當前位置的堆棧資訊,它被log_helper.py包的error()錯誤記錄檔記錄函數調用,輸出發生錯誤時的堆棧資訊內容,方便開發人員分析代碼異常。
#!/usr/bin/evn python# coding=utf-8import osimport sysdef 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-8import jsonimport datetimeclass 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------ErrorTraceback (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
出處:http://www.cnblogs.com/EmptyFS/
有興趣的朋友可以加加python開發QQ群:669058475 ,大家一起探討。大家有問題的話可以在群裡發問,當然我平時工作也非常繁忙不一定會及時回複。
本文為AllEmpty原創,歡迎轉載,但未經同意必須保留此段聲明,且在文章頁面明顯位置給出原文串連,否則保留追究法律責任的權利。