python开发框架 代码生成_我的第一个python web开发框架(31)——定制ORM(七)...
幾個復雜的ORM方式都已介紹完了,剩下一些常用的刪除、獲取記錄數量、統計合計數、獲取最大值、獲取最小值等方法我就不一一詳細介紹了,直接給出代碼大家自行查看。
1 #!/usr/bin/env python
2 #coding=utf-8
3
4 from common importdb_helper5
6
7 classLogicBase():8 """邏輯層基礎類"""
9
10 def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):11 """類初始化"""
12 #數據庫參數
13 self.__db =db14 #是否輸出執行的Sql語句到日志中
15 self.__is_output_sql =is_output_sql16 #表名稱
17 self.__table_name =str(table_name).lower()18 #查詢的列字段名稱,*表示查詢全部字段,多于1個字段時用逗號進行分隔,除了字段名外,也可以是表達式
19 self.__column_name_list =str(column_name_list).lower()20 #主健名稱
21 self.__pk_name =str(pk_name).lower()22
23 #####################################################################
24 ### 執行Sql ###
25
26 defselect(self, sql):27 """執行sql查詢語句(select)"""
28 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:29 #執行sql語句
30 result =db.execute(sql)31 if notresult:32 result =[]33 returnresult34
35 defexecute(self, sql):36 """執行sql語句,并提交事務"""
37 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:38 #執行sql語句
39 result =db.execute(sql)40 ifresult:41 db.commit()42 else:43 result =[]44 returnresult45
46 defcopy(self, values, columns):47 """批量更新數據"""
48 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:49 #執行sql語句
50 result = db.copy(values, self.__table_name, columns)51 returnresult52
53 defget_model(self, wheres):54 """通過條件獲取一條記錄"""
55 #如果有條件,則自動添加where
56 ifwheres:57 wheres = 'where' +wheres58
59 #合成sql語句
60 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" %\61 {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}62 #初化化數據庫鏈接
63 result =self.select(sql)64 ifresult:65 returnresult[0]66 return{}67
68 def get_model_for_pk(self, pk, wheres=''):69 """通過主鍵值獲取數據庫記錄實體"""
70 if notpk:71 return{}72 #組裝查詢條件
73 wheres = '%s = %s' % (self.__pk_name, str(pk))74
75 returnself.get_model(wheres)76
77 def get_value(self, column_name, wheres=''):78 """
79 獲取指定條件的字段值————多于條記錄時,只取第一條記錄80 :param column_name: 單個字段名,如:id81 :param wheres: 查詢條件82 :return: 7 (指定的字段值)83 """
84 if notcolumn_name:85 returnNone86 elifwheres:87 wheres = 'where' +wheres88
89 sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' %\90 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}91 result =self.select(sql)92 #如果查詢成功,則直接返回記錄字典
93 ifresult:94 returnresult[0].get(column_name)95
96 def get_value_list(self, column_name, wheres=''):97 """
98 獲取指定條件記錄的字段值列表99 :param column_name: 單個字段名,如:id100 :param wheres: 查詢條件101 :return: [1,3,4,6,7]102 """
103 if notcolumn_name:104 column_name = self.__pk_name
105 elifwheres:106 wheres = 'where' +wheres107
108 sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' %\109 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}110 result =self.select(sql)111 #如果查詢失敗或不存在指定條件記錄,則直接返回初始值
112 if result andisinstance(result, list):113 return result[0].get('list')114 else:115 return[]116
117 def add_model(self, fields, returning=''):118 """新增數據庫記錄"""
119 ### 拼接sql語句 ###
120 #初始化變量
121 key_list =[]122 value_list =[]123 #將傳入的字典參數進行處理,把字段名生成sql插入字段名數組和字典替換數組
124 #PS:字符串使用字典替換參數時,格式是%(name)s,這里會生成對應的字串
125 #比如:
126 #傳入的字典為: {'id': 1, 'name': '名稱'}
127 #那么生成的key_list為:'id','name'
128 #而value_list為:'%(id)s,%(name)s'
129 #最終而value_list為字符串對應名稱位置會被替換成相應的值
130 for key infields.keys():131 key_list.append(key)132 value_list.append('%(' + key + ')s')133 #設置sql拼接字典,并將數組(lit)使用join方式進行拼接,生成用逗號分隔的字符串
134 parameter ={135 'table_name': self.__table_name,136 'pk_name': self.__pk_name,137 'key_list': ','.join(key_list),138 'value_list': ','.join(value_list)139 }140 #如果有指定返回參數,則添加
141 ifreturning:142 parameter['returning'] = ',' +returning143 else:144 parameter['returning'] = ''
145
146 #生成可以使用字典替換的字符串
147 sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" %parameter148 #將生成好的字符串替字典參數值,生成最終可執行的sql語句
149 sql = sql %fields150
151 result =self.execute(sql)152 ifresult:153 returnresult[0]154 return{}155
156 def edit(self, fields, wheres='', returning=''):157 """批量編輯數據庫記錄"""
158 ### 拼接sql語句 ###
159 #拼接字段與值
160 field_list = [key + '= %(' + key + ')s' for key infields.keys()]161 #設置sql拼接字典
162 parameter ={163 'table_name': self.__table_name,164 'pk_name': self.__pk_name,165 'field_list': ','.join(field_list)166 }167 #如果存在更新條件,則將條件添加到sql拼接更換字典中
168 ifwheres:169 parameter['wheres'] = 'where' +wheres170 else:171 parameter['wheres'] = ''
172
173 #如果有指定返回參數,則添加
174 ifreturning:175 parameter['returning'] = ',' +returning176 else:177 parameter['returning'] = ''
178
179 #生成sql語句
180 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" %parameter181 sql = sql %fields182
183 returnself.execute(sql)184
185 def edit_model(self, pk, fields, wheres='', returning=''):186 """編輯單條數據庫記錄"""
187 if notpk:188 return{}189 elifwheres:190 wheres = self.__pk_name + '=' + str(pk) + 'and' +wheres191 else:192 wheres = self.__pk_name + '=' +str(pk)193
194 returnself.edit(fields, wheres, returning)195
196 def delete(self, wheres='', returning='', is_update_cache=True):197 """批量刪除數據庫記錄"""
198 #如果存在條件
199 ifwheres:200 wheres = 'where' +wheres201
202 #如果有指定返回參數,則添加
203 ifreturning:204 returning = ',' +returning205
206 #生成sql語句
207 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" %\208 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}209 returnself.execute(sql)210
211 def delete_model(self, pk, wheres='', returning='', is_update_cache=True):212 """刪除單條數據庫記錄"""
213 if notpk:214 return{}215 elifwheres:216 wheres = self.__pk_name + '=' + str(pk) + 'and' +wheres217 else:218 wheres = self.__pk_name + '=' +str(pk)219
220 returnself.delete(wheres, returning)221
222 def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None):223 """
224 獲取指定條件的數據庫記錄集225 :param column_name_list: 查詢字段226 :param wheres: 查詢條件227 :param page_number: 分頁索引值228 :param page_size: 分頁大小, 存在值時才會執行分頁229 :param orderby: 排序規則230 :param table_name: 查詢數據表,多表查詢時需要設置231 :return: 返回記錄集總數量與分頁記錄集232 {'records': 0, 'total': 0, 'page': 0, 'rows': []}233 """
234 #初始化輸出參數:總記錄數量與列表集
235 data ={236 'records': 0, #總記錄數
237 'total': 0, #總頁數
238 'page': 1, #當前頁面索引
239 'rows': [], #查詢結果(記錄列表)
240 }241 #初始化查詢數據表名稱
242 if nottable_name:243 table_name = self.__table_name
244 #初始化查詢字段名
245 if notcolumn_name_list:246 column_name_list = self.__column_name_list
247 #初始化查詢條件
248 ifwheres:249 #如果是字符串,表示該查詢條件已組裝好了,直接可以使用
250 ifisinstance(wheres, str):251 wheres = 'where' +wheres252 #如果是list,則表示查詢條件有多個,可以使用join將它們用and方式組合起來使用
253 elifisinstance(wheres, list):254 wheres = 'where' + 'and'.join(wheres)255 #初始化排序
256 if notorderby:257 orderby = self.__pk_name + 'desc'
258 #初始化分頁查詢的記錄區間
259 paging = ''
260
261 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:262 #############################################################
263 #判斷是否需要進行分頁
264 if not page_size isNone:265 ### 執行sql,獲取指定條件的記錄總數量
266 sql = 'select count(1) as records from %(table_name)s %(wheres)s' %\267 {'table_name': table_name, 'wheres': wheres}268 result =db.execute(sql)269 #如果查詢失敗或不存在指定條件記錄,則直接返回初始值
270 if not result or result[0]['records'] ==0:271 returndata272
273 #設置記錄總數量
274 data['records'] = result[0].get('records')275
276 #########################################################
277 ### 設置分頁索引與頁面大小 ###
278 if page_size <=0:279 page_size = 10
280 #計算總分頁數量:通過總記錄數除于每頁顯示數量來計算總分頁數量
281 if data['records'] % page_size ==0:282 page_total = data['records'] //page_size283 else:284 page_total = data['records'] // page_size + 1
285 #判斷頁碼是否超出限制,超出限制查詢時會出現異常,所以將頁面索引設置為最后一頁
286 if page_number < 1 or page_number >page_total:287 page_number =page_total288 #記錄總頁面數量
289 data['total'] =page_total290 #記錄當前頁面值
291 data['page'] =page_number292 #計算當前頁面要顯示的記錄起始位置(limit指定的位置)
293 record_number = (page_number - 1) *page_size294 #設置查詢分頁條件
295 paging = 'limit' + str(page_size) + 'offset' +str(record_number)296 #############################################################
297
298 ### 按條件查詢數據庫記錄
299 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" %\300 {'column_name_list': column_name_list,301 'table_name': table_name,302 'wheres': wheres,303 'orderby': orderby,304 'paging': paging}305 result =db.execute(sql)306 ifresult:307 data['rows'] =result308 #不需要分頁查詢時,直接在這里設置總記錄數
309 if page_size isNone:310 data['records'] =len(result)311
312 returndata313
314 def get_count(self, wheres=''):315 """獲取指定條件記錄數量"""
316 ifwheres:317 wheres = 'where' +wheres318 sql = 'select count(1) as total from %(table_name)s %(wheres)s' %\319 {'table_name': self.__table_name, 'wheres': wheres}320 result =self.select(sql)321 #如果查詢存在記錄,則返回true
322 ifresult:323 return result[0].get('total')324 return0325
326 defget_sum(self, fields, wheres):327 """獲取指定條件記錄數量"""
328 sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s' %\329 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}330 result =self.select(sql)331 #如果查詢存在記錄,則返回true
332 if result and result[0].get('total'):333 return result[0].get('total')334 return0335
336 defget_min(self, fields, wheres):337 """獲取該列記錄最小值"""
338 sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s' %\339 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}340 result =self.select(sql)341 #如果查詢存在記錄,則返回true
342 if result and result[0].get('min'):343 return result[0].get('min')344
345 defget_max(self, fields, wheres):346 """獲取該列記錄最大值"""
347 sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s' %\348 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}349 result =self.select(sql)350 #如果查詢存在記錄,則返回true
351 if result and result[0].get('max'):352 return result[0].get('max')353
354 #####################################################################
View Code
大家只要掌握了ORM簡單的組合sql方法,就可以自由發揮,根據自己的需要去創建不同的方法了,也可以隨意更換mysql、mssql等數據庫。
當然,這只是最簡單的ORM方式,提交字段參數和條件參數時,它不會自動分辨字段的類型,不會自動初始化默認值,如果想讓它變的更加強大,還需要做更多的改造與處理,這樣做的話它也會跟著變的更加復雜和難懂,性能也會跟著下降。不過當前功能對于多數項目來說,已經足夠使用了。大家如果有需要可以自行研究進行擴展。
在日常操作中,獲取指定記錄實體是最常見使用最頻繁的操作,為了減少對數據庫的查詢,我們可以將ORM與Nosql結合起來,提升ORM的操作性能,當然如果你不想使用nosql緩存,也可以直接跳過本章節。
使用Nosql,首先我們需要一個鏈接Nosql的配置文件,用它來存儲Nosql的服務地址、端口、密碼等參數
在config文件夾中我們創建redis_config.py配置文件
#!/usr/bin/env python#coding=utf-8
### redis緩存配置參數 ###
REDIS ={#服務地址
'server': '127.0.0.1',#服務端口
'post': 6379,#服務密碼
'pwd': '',#數據庫序號
'db': 1}
然后我們還需要一個nosql鏈接工具包(cache_helper.py),用來對nosql進行set、get、delete和clear操作(存儲、獲取、刪除和清空緩存)
1 #!/usr/bin/env python
2 #coding=utf-8
3
4 importredis5
6 from common importlog_helper7 from config importredis_config8
9 #設置redis配置參數
10 _redis =redis_config.REDIS11 #初始化Redis緩存鏈接
12 r =None13 try:14 if notr:15 r = redis.Redis(host=_redis.get('server', ''),16 port=_redis.get('post', ''),17 db=_redis.get('db', ''),18 password=_redis.get('pwd', ''),19 socket_timeout=1,20 socket_connect_timeout=1)21 exceptException as e:22 log_helper.info('連接redis出錯:(' + str(_redis) + ')' +str(e.args))23 pass
24
25
26 def set(key, value, time=86400):27 """
28 寫緩存29 :param key: 緩存key,字符串,不區分大小寫30 :param value: 要存儲的值31 :param time: 緩存過期時間(單位:秒),0=永不過期32 :return:33 """
34 #將key轉換為小寫字母
35 key =str(key).lower()36 try:37 r.set(key, value, time)38 exceptException as e:39 log_helper.info('寫緩存失敗:key(' + key + ')' +str(e.args))40 pass
41
42
43 defget(key):44 """
45 讀緩存46 :param key: 緩存key,字符串,不區分大小寫47 :return:48 """
49 #將key轉換為小寫字母
50 key =str(key).lower()51 try:52 value =r.get(key)53 exceptException as e:54 #log_helper.error('讀緩存失敗:key(' + key + ')' + str(e.args) + ' r:' + str(r) + ' _redis:' + str(_redis))
55 value =None56
57 return_str_to_json(value)58
59
60 defpush(key, value):61 """
62 添加數據到隊列頭部63 :param key: 緩存key,字符串,不區分大小寫64 :param value: 要存儲的值65 """
66 #將key轉換為小寫字母
67 key =str(key).lower()68 try:69 r.lpush(key, value)70 exceptException as e:71 log_helper.info('寫緩存失敗:key(' + key + ')' +str(e.args))72 pass
73
74
75 defpop(key):76 """
77 從緩存隊列的后尾讀取一條數據78 :param key: 緩存key,字符串,不區分大小寫79 :return: 緩存數據80 """
81 #將key轉換為小寫字母
82 key =str(key).lower()83 try:84 value =r.rpop(key)85 exceptException as e:86 log_helper.info('讀取緩存隊列失敗:key(' + key + ')' +str(e.args))87 value =None88
89 return_str_to_json(value)90
91
92 def_str_to_json(value):93 """
94 將緩存中讀取出來的字符串轉換成對應的數據、元組、列表或字典95 """
96 if notvalue:97 returnvalue98 #否則直接轉換
99 try:100 value =value.decode()101 returneval(value)102 exceptException as e:103 print(e.args)104 pass
105 #否則直接輸出字符串
106 returnvalue107
108
109 defdelete(key):110 """
111 刪除緩存112 :param key:緩存key,字符串,不區分大小寫113 :return:114 """
115 #將key轉換為小寫字母
116 key =str(key).lower()117 try:118 log_helper.info(str(r.delete(key)))119 exceptException as e:120 log_helper.info('Exception:' +str(e.args))121 pass
122
123
124 defclear():125 """
126 清空所有緩存127 """
128 try:129 r.flushdb()130 except:131 pass
View Code
我常用的是redis,所以使用cache_helper.py時,需要安裝redis服務和對應的Python包。如果你使用的是memcache,你只需要重構一下cache_helper.py代碼就可以了。
接下來我們改造一下邏輯層基類(ORM模塊)
首先我們需要導入cache_helper
from common import db_helper, cache_helper
在使用nosql緩存時,大家都知道我們是使用key來進行對象存取的,而這個key也是唯一的,所以key的生成就很重要的,為了避免key的重復,我們在對記錄設置key時,可以用表名+主鍵id的方式來組合key,當然為了調用方便,可以將獲取key寫成一個方法來生成
defget_cache_key(self, pk):"""獲取緩存key值"""
return ''.join((self.__table_name, '_', str(pk)))
這里使用join的方法,將表名、下橫線、主鍵值組合生成緩存key字符串
對于緩存的操作,主要有設置緩存、獲取緩存、刪除緩存這三種操作,當然為了方便我們獲取記錄中指定字段值,我們可以增加讀取指定字段值方法。
首先是設置緩存方法,大家看看下面代碼,它非常簡單,先調用生成緩存key,然后將對象存儲到緩存中,并指定過期時間,當設置time為0時,它將永不過期
def set_model_for_cache(self, pk, value, time=43200):"""更新存儲在緩存中的數據庫記錄,緩存過期時間為12小時"""
#生成緩存key
key =self.get_cache_key(pk)#存儲到nosql緩存中
cache_helper.set(key, value, time)
接著是獲取緩存對象方法
defget_model_for_cache(self, pk):"""從緩存中讀取數據庫記錄"""
#生成緩存key
key =self.get_cache_key(pk)#從緩存中讀取數據庫記錄
result =cache_helper.get(key)#緩存中不存在記錄,則從數據庫獲取
if notresult:
result=self.get_model_for_pk(pk)
self.set_model_for_cache(pk, result)ifresult:returnresultelse:return {}
我們首先要做的同樣是生成緩存key,然后調用get方法從緩存中讀取對象,執行完后,需要判斷該對象是否存在緩存中,如果不存在則表示該對象并未存儲到緩存中或它可能存儲過期了,所以需要重新從數據庫中讀取出來,并將它存儲到緩存中,然后將讀取出來的記錄實體返回出去。
然后我們再增加一個讀取指定記錄字段值的方法
defget_value_for_cache(self, pk, column_name):"""獲取指定記錄的字段值"""
return self.get_model_for_cache(pk).get(column_name)
它直接調用獲取緩存對象方法,然后從返回的對象中讀取指定的字段值就可以了
刪除緩存方法也很簡單,生成緩存key后,直接調用delete進行刪除。對于刪除方法,有時候調用不知是不是nosql自身bug問題,還是在主從關系的nosql中讀寫分離會引起刪除失敗,如果出現這種情況,可以將delete改為set,將該緩存set為空就可以解決這個問題
defdel_model_for_cache(self, pk):"""刪除緩存中指定數據"""
#生成緩存key
key =self.get_cache_key(pk)#log_helper.info(key)
#存儲到nosql緩存中
cache_helper.delete(key)
PS:在使用緩存操作時,有時我們直接對數據庫進行操作,就會引起數據與緩存不匹配,出現臟數據的情況,這時在后臺增加清空緩存的操作,直接調用cache_helper.clear()進行清空緩存。
基本方法都完成了,接下來就是要對ORM的刪除與修改方法進行改造了,讓它們自行根據需要對緩存進行對應操作,讓緩存與數據表中的記錄保持一致。
在改造時,我們只需要對刪除與修改操作進行處理,對新增與查詢操作不需要操作,因為新增的記錄,它并在緩存中并不存在,所以不需要進行操作,而查詢也不會改變數據內容,只有進行刪除和修改操作時,才會變動數據內容,這時就需要更改緩存,讓數據保持一致。
改造編輯記錄實體方法
1 def edit(self, fields, wheres='', returning='', is_update_cache=True):2 """
3 批量編輯數據庫記錄4 :param fields: 要更新的字段(字段名與值存儲在字典中)5 :param wheres: 更新條件6 :param returning: 更新成功后,返回的字段名7 :param is_update_cache: 是否同步更新緩存8 :return:9 """
10 ### 拼接sql語句 ###
11 #拼接字段與值
12 field_list = [key + '= %(' + key + ')s' for key infields.keys()]13 #設置sql拼接字典
14 parameter ={15 'table_name': self.__table_name,16 'pk_name': self.__pk_name,17 'field_list': ','.join(field_list)18 }19 #如果存在更新條件,則將條件添加到sql拼接更換字典中
20 ifwheres:21 parameter['wheres'] = 'where' +wheres22 else:23 parameter['wheres'] = ''
24
25 #如果有指定返回參數,則添加
26 ifreturning:27 parameter['returning'] = ',' +returning28 else:29 parameter['returning'] = ''
30
31 #生成sql語句
32 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" %parameter33 sql = sql %fields34
35 result =self.execute(sql)36 ifresult:37 #判斷是否刪除對應的緩存
38 ifis_update_cache:39 #循環刪除更新成功的所有記錄對應的緩存
40 for model inresult:41 self.del_model_for_cache(model.get('id', 0))42 return result
大家可以看到,該方法增加了is_update_cache?是否同步更新緩存參數,這是因為我們在使用緩存時會存在一些特殊情況,比如說批量更新很多數據時,如果使用循環逐條清理對應緩存時,會占用較多資源,我們可以關掉緩存的同步更新,直接調用clear清空所有緩存會更加快捷;又比如說,頁面訪問數的更新,它會更新的非常頻繁,我們不需要實時清除,可以使用其他方式觸發清理,也可以將點擊數用獨立緩存存儲使用等
而清理緩存,我們只需要將緩存內容直接刪除就可以了,因為執行更新以后,返回的記錄實體沒有設置為*時,只返回主鍵id,直接設置的話會造成緩存數據丟失細節的問題,另外,我們執行更新以后,該記錄也不一定還會被讀取出來。
刪除記錄也進行一樣的改造
1 def delete(self, wheres='', returning='', is_update_cache=True):2 """
3 批量刪除數據庫記錄4 :param wheres: 刪除條件5 :param returning: 刪除成功后,返回的字段名6 :param is_update_cache: 是否同步更新緩存7 :return:8 """
9 #如果存在條件
10 ifwheres:11 wheres = 'where' +wheres12
13 #如果有指定返回參數,則添加
14 ifreturning:15 returning = ',' +returning16
17 #生成sql語句
18 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" %\19 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}20 result =self.execute(sql)21 ifresult:22 #同步刪除對應的緩存
23 ifis_update_cache:24 for model inresult:25 self.del_model_for_cache(model.get('id', 0))26 return result
對于緩存基本上就這兩個要進行改造的操作了。在實現開發中,我們認真想一想,其實我們還會存在一些特殊的情況,比如說我們對數據進行加工處理后,將加工后的值存儲到緩存中,而對相關記錄進行修改或刪除操作以后,由于這些緩存它與記錄并沒有關聯,所以執行相關操作以后,它就變成孤島,不會實時同步,產生臟數據。所以我們需要有一個功能,可以將它們管理起來,與該數據表的修改和刪除操作關聯起來,進行修改和刪除操作后同步清除這些特殊緩存。
根據這些要求,我們就需要再增加兩個緩存操作方法,用來存儲這些特殊的緩存名稱,然后在進行修改和刪除操作時,同步清除這些特殊緩存。
首先我們需要在初始化方法中,添加一個綁定該數據表的全局緩存變量self.__cache_list,它由表名稱+_cache_list組成。
1 def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):2 """類初始化"""
3 #數據庫參數
4 self.__db =db5 #是否輸出執行的Sql語句到日志中
6 self.__is_output_sql =is_output_sql7 #表名稱
8 self.__table_name =str(table_name).lower()9 #查詢的列字段名稱,*表示查詢全部字段,多于1個字段時用逗號進行分隔,除了字段名外,也可以是表達式
10 self.__column_name_list =str(column_name_list).lower()11 #主健名稱
12 self.__pk_name =str(pk_name).lower()13 #緩存列表
14 self.__cache_list = self.__table_name + '_cache_list'
然后我們再添加特殊緩存存儲方法
1 defadd_relevance_cache_in_list(self, key):2 """將緩存名稱存儲到列表里————主要存儲與記錄變更關聯的"""
3 #從nosql中讀取全局緩存列表
4 cache_list = cache_helper.get(self.__cache_list)5 #判斷緩存列表是否有值,有則進行添加操作
6 ifcache_list:7 #判斷是否已存儲列表中,不存在則執行添加操作
8 if not key incache_list:9 cache_list.append(key)10 cache_helper.set(self.__cache_list, cache_list)11 #無則直接創建全局緩存列表,并存儲到nosql中
12 else:13 cache_list =[key]14 cache_helper.set(self.__cache_list, cache_list)
執行該方法,會將我們自定義的緩存名稱存儲到全局緩存變量中
接著我們再添加一個清除所有特殊緩存的方法
1 defdel_relevance_cache(self):2 """刪除關聯緩存————將和數據表記錄關聯的,個性化緩存全部刪除"""
3 #從nosql中讀取全局緩存列表
4 cache_list = cache_helper.get(self.__cache_list)5 #清除已刪除緩存列表
6 cache_helper.delete(self.__cache_list)7 ifcache_list:8 #執行刪除操作
9 for cache incache_list:10 cache_helper.delete(cache)
添加完成以后,我們再來改造一下修改與刪除代碼,只需要在里面添加清除所有特殊緩存方法就可以了
1 def edit(self, fields, wheres='', returning='', is_update_cache=True):2 """
3 批量編輯數據庫記錄4 :param fields: 要更新的字段(字段名與值存儲在字典中)5 :param wheres: 更新條件6 :param returning: 更新成功后,返回的字段名7 :param is_update_cache: 是否同步更新緩存8 :return:9 """
10 ### 拼接sql語句 ###
11 #拼接字段與值
12 field_list = [key + '= %(' + key + ')s' for key infields.keys()]13 #設置sql拼接字典
14 parameter ={15 'table_name': self.__table_name,16 'pk_name': self.__pk_name,17 'field_list': ','.join(field_list)18 }19 #如果存在更新條件,則將條件添加到sql拼接更換字典中
20 ifwheres:21 parameter['wheres'] = 'where' +wheres22 else:23 parameter['wheres'] = ''
24
25 #如果有指定返回參數,則添加
26 ifreturning:27 parameter['returning'] = ',' +returning28 else:29 parameter['returning'] = ''
30
31 #生成sql語句
32 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" %parameter33 sql = sql %fields34
35 result =self.execute(sql)36 ifresult:37 #判斷是否刪除對應的緩存
38 ifis_update_cache:39 #循環刪除更新成功的所有記錄對應的緩存
40 for model inresult:41 self.del_model_for_cache(model.get('id', 0))42 #同步刪除與本表關聯的緩存
43 self.del_relevance_cache()44 returnresult45
46 def delete(self, wheres='', returning='', is_update_cache=True):47 """
48 批量刪除數據庫記錄49 :param wheres: 刪除條件50 :param returning: 刪除成功后,返回的字段名51 :param is_update_cache: 是否同步更新緩存52 :return:53 """
54 #如果存在條件
55 ifwheres:56 wheres = 'where' +wheres57
58 #如果有指定返回參數,則添加
59 ifreturning:60 returning = ',' +returning61
62 #生成sql語句
63 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" %\64 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}65 result =self.execute(sql)66 ifresult:67 #同步刪除對應的緩存
68 ifis_update_cache:69 for model inresult:70 self.del_model_for_cache(model.get('id', 0))71 #同步刪除與本表關聯的緩存
72 self.del_relevance_cache()73 return result
View Code
ORM的緩存改造就全部完成了,下面是完整代碼
1 #!/usr/bin/env python
2 #coding=utf-8
3
4 from common importdb_helper, cache_helper5
6
7 classLogicBase():8 """邏輯層基礎類"""
9
10 def __init__(self, db, is_output_sql, table_name, column_name_list='*', pk_name='id'):11 """類初始化"""
12 #數據庫參數
13 self.__db =db14 #是否輸出執行的Sql語句到日志中
15 self.__is_output_sql =is_output_sql16 #表名稱
17 self.__table_name =str(table_name).lower()18 #查詢的列字段名稱,*表示查詢全部字段,多于1個字段時用逗號進行分隔,除了字段名外,也可以是表達式
19 self.__column_name_list =str(column_name_list).lower()20 #主健名稱
21 self.__pk_name =str(pk_name).lower()22 #緩存列表
23 self.__cache_list = self.__table_name + '_cache_list'
24
25 #####################################################################
26 ### 執行Sql ###
27
28 defselect(self, sql):29 """執行sql查詢語句(select)"""
30 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:31 #執行sql語句
32 result =db.execute(sql)33 if notresult:34 result =[]35 returnresult36
37 defexecute(self, sql):38 """執行sql語句,并提交事務"""
39 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:40 #執行sql語句
41 result =db.execute(sql)42 ifresult:43 db.commit()44 else:45 result =[]46 returnresult47
48 defcopy(self, values, columns):49 """批量更新數據"""
50 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:51 #執行sql語句
52 result = db.copy(values, self.__table_name, columns)53 returnresult54
55 defget_model(self, wheres):56 """通過條件獲取一條記錄"""
57 #如果有條件,則自動添加where
58 ifwheres:59 wheres = 'where' +wheres60
61 #合成sql語句
62 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s" %\63 {'column_name_list': self.__column_name_list, 'table_name': self.__table_name, 'wheres': wheres}64 #初化化數據庫鏈接
65 result =self.select(sql)66 ifresult:67 returnresult[0]68 return{}69
70 def get_model_for_pk(self, pk, wheres=''):71 """通過主鍵值獲取數據庫記錄實體"""
72 if notpk:73 return{}74 #組裝查詢條件
75 wheres = '%s = %s' % (self.__pk_name, str(pk))76
77 returnself.get_model(wheres)78
79 def get_value(self, column_name, wheres=''):80 """
81 獲取指定條件的字段值————多于條記錄時,只取第一條記錄82 :param column_name: 單個字段名,如:id83 :param wheres: 查詢條件84 :return: 7 (指定的字段值)85 """
86 if notcolumn_name:87 returnNone88 elifwheres:89 wheres = 'where' +wheres90
91 sql = 'select %(column_name)s from %(table_name)s %(wheres)s limit 1' %\92 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}93 result =self.select(sql)94 #如果查詢成功,則直接返回記錄字典
95 ifresult:96 returnresult[0].get(column_name)97
98 def get_value_list(self, column_name, wheres=''):99 """
100 獲取指定條件記錄的字段值列表101 :param column_name: 單個字段名,如:id102 :param wheres: 查詢條件103 :return: [1,3,4,6,7]104 """
105 if notcolumn_name:106 column_name = self.__pk_name
107 elifwheres:108 wheres = 'where' +wheres109
110 sql = 'select array_agg(%(column_name)s) as list from %(table_name)s %(wheres)s' %\111 {'column_name': column_name, 'table_name': self.__table_name, 'wheres': wheres}112 result =self.select(sql)113 #如果查詢失敗或不存在指定條件記錄,則直接返回初始值
114 if result andisinstance(result, list):115 return result[0].get('list')116 else:117 return[]118
119 def add_model(self, fields, returning=''):120 """新增數據庫記錄"""
121 ### 拼接sql語句 ###
122 #初始化變量
123 key_list =[]124 value_list =[]125 #將傳入的字典參數進行處理,把字段名生成sql插入字段名數組和字典替換數組
126 #PS:字符串使用字典替換參數時,格式是%(name)s,這里會生成對應的字串
127 #比如:
128 #傳入的字典為: {'id': 1, 'name': '名稱'}
129 #那么生成的key_list為:'id','name'
130 #而value_list為:'%(id)s,%(name)s'
131 #最終而value_list為字符串對應名稱位置會被替換成相應的值
132 for key infields.keys():133 key_list.append(key)134 value_list.append('%(' + key + ')s')135 #設置sql拼接字典,并將數組(lit)使用join方式進行拼接,生成用逗號分隔的字符串
136 parameter ={137 'table_name': self.__table_name,138 'pk_name': self.__pk_name,139 'key_list': ','.join(key_list),140 'value_list': ','.join(value_list)141 }142 #如果有指定返回參數,則添加
143 ifreturning:144 parameter['returning'] = ',' +returning145 else:146 parameter['returning'] = ''
147
148 #生成可以使用字典替換的字符串
149 sql = "insert into %(table_name)s (%(key_list)s) values (%(value_list)s) returning %(pk_name)s %(returning)s" %parameter150 #將生成好的字符串替字典參數值,生成最終可執行的sql語句
151 sql = sql %fields152
153 result =self.execute(sql)154 ifresult:155 returnresult[0]156 return{}157
158 def edit(self, fields, wheres='', returning='', is_update_cache=True):159 """
160 批量編輯數據庫記錄161 :param fields: 要更新的字段(字段名與值存儲在字典中)162 :param wheres: 更新條件163 :param returning: 更新成功后,返回的字段名164 :param is_update_cache: 是否同步更新緩存165 :return:166 """
167 ### 拼接sql語句 ###
168 #拼接字段與值
169 field_list = [key + '= %(' + key + ')s' for key infields.keys()]170 #設置sql拼接字典
171 parameter ={172 'table_name': self.__table_name,173 'pk_name': self.__pk_name,174 'field_list': ','.join(field_list)175 }176 #如果存在更新條件,則將條件添加到sql拼接更換字典中
177 ifwheres:178 parameter['wheres'] = 'where' +wheres179 else:180 parameter['wheres'] = ''
181
182 #如果有指定返回參數,則添加
183 ifreturning:184 parameter['returning'] = ',' +returning185 else:186 parameter['returning'] = ''
187
188 #生成sql語句
189 sql = "update %(table_name)s set %(field_list)s %(wheres)s returning %(pk_name)s %(returning)s" %parameter190 sql = sql %fields191
192 result =self.execute(sql)193 ifresult:194 #判斷是否刪除對應的緩存
195 ifis_update_cache:196 #循環刪除更新成功的所有記錄對應的緩存
197 for model inresult:198 self.del_model_for_cache(model.get('id', 0))199 #同步刪除與本表關聯的緩存
200 self.del_relevance_cache()201 returnresult202
203 def edit_model(self, pk, fields, wheres='', returning=''):204 """編輯單條數據庫記錄"""
205 if notpk:206 return{}207 elifwheres:208 wheres = self.__pk_name + '=' + str(pk) + 'and' +wheres209 else:210 wheres = self.__pk_name + '=' +str(pk)211
212 returnself.edit(fields, wheres, returning)213
214 def delete(self, wheres='', returning='', is_update_cache=True):215 """
216 批量刪除數據庫記錄217 :param wheres: 刪除條件218 :param returning: 刪除成功后,返回的字段名219 :param is_update_cache: 是否同步更新緩存220 :return:221 """
222 #如果存在條件
223 ifwheres:224 wheres = 'where' +wheres225
226 #如果有指定返回參數,則添加
227 ifreturning:228 returning = ',' +returning229
230 #生成sql語句
231 sql = "delete from %(table_name)s %(wheres)s returning %(pk_name)s %(returning)s" %\232 {'table_name': self.__table_name, 'wheres': wheres, 'pk_name': self.__pk_name, 'returning': returning}233 result =self.execute(sql)234 ifresult:235 #同步刪除對應的緩存
236 ifis_update_cache:237 for model inresult:238 self.del_model_for_cache(model.get('id', 0))239 #同步刪除與本表關聯的緩存
240 self.del_relevance_cache()241 returnresult242
243 def delete_model(self, pk, wheres='', returning='', is_update_cache=True):244 """刪除單條數據庫記錄"""
245 if notpk:246 return{}247 elifwheres:248 wheres = self.__pk_name + '=' + str(pk) + 'and' +wheres249 else:250 wheres = self.__pk_name + '=' +str(pk)251
252 returnself.delete(wheres, returning)253
254 def get_list(self, column_name_list='', wheres='', page_number=None, page_size=None, orderby=None, table_name=None):255 """
256 獲取指定條件的數據庫記錄集257 :param column_name_list: 查詢字段258 :param wheres: 查詢條件259 :param page_number: 分頁索引值260 :param page_size: 分頁大小, 存在值時才會執行分頁261 :param orderby: 排序規則262 :param table_name: 查詢數據表,多表查詢時需要設置263 :return: 返回記錄集總數量與分頁記錄集264 {'records': 0, 'total': 0, 'page': 0, 'rows': []}265 """
266 #初始化輸出參數:總記錄數量與列表集
267 data ={268 'records': 0, #總記錄數
269 'total': 0, #總頁數
270 'page': 1, #當前頁面索引
271 'rows': [], #查詢結果(記錄列表)
272 }273 #初始化查詢數據表名稱
274 if nottable_name:275 table_name = self.__table_name
276 #初始化查詢字段名
277 if notcolumn_name_list:278 column_name_list = self.__column_name_list
279 #初始化查詢條件
280 ifwheres:281 #如果是字符串,表示該查詢條件已組裝好了,直接可以使用
282 ifisinstance(wheres, str):283 wheres = 'where' +wheres284 #如果是list,則表示查詢條件有多個,可以使用join將它們用and方式組合起來使用
285 elifisinstance(wheres, list):286 wheres = 'where' + 'and'.join(wheres)287 #初始化排序
288 if notorderby:289 orderby = self.__pk_name + 'desc'
290 #初始化分頁查詢的記錄區間
291 paging = ''
292
293 with db_helper.PgHelper(self.__db, self.__is_output_sql) as db:294 #############################################################
295 #判斷是否需要進行分頁
296 if not page_size isNone:297 ### 執行sql,獲取指定條件的記錄總數量
298 sql = 'select count(1) as records from %(table_name)s %(wheres)s' %\299 {'table_name': table_name, 'wheres': wheres}300 result =db.execute(sql)301 #如果查詢失敗或不存在指定條件記錄,則直接返回初始值
302 if not result or result[0]['records'] ==0:303 returndata304
305 #設置記錄總數量
306 data['records'] = result[0].get('records')307
308 #########################################################
309 ### 設置分頁索引與頁面大小 ###
310 if page_size <=0:311 page_size = 10
312 #計算總分頁數量:通過總記錄數除于每頁顯示數量來計算總分頁數量
313 if data['records'] % page_size ==0:314 page_total = data['records'] //page_size315 else:316 page_total = data['records'] // page_size + 1
317 #判斷頁碼是否超出限制,超出限制查詢時會出現異常,所以將頁面索引設置為最后一頁
318 if page_number < 1 or page_number >page_total:319 page_number =page_total320 #記錄總頁面數量
321 data['total'] =page_total322 #記錄當前頁面值
323 data['page'] =page_number324 #計算當前頁面要顯示的記錄起始位置(limit指定的位置)
325 record_number = (page_number - 1) *page_size326 #設置查詢分頁條件
327 paging = 'limit' + str(page_size) + 'offset' +str(record_number)328 #############################################################
329
330 ### 按條件查詢數據庫記錄
331 sql = "select %(column_name_list)s from %(table_name)s %(wheres)s order by %(orderby)s %(paging)s" %\332 {'column_name_list': column_name_list,333 'table_name': table_name,334 'wheres': wheres,335 'orderby': orderby,336 'paging': paging}337 result =db.execute(sql)338 ifresult:339 data['rows'] =result340 #不需要分頁查詢時,直接在這里設置總記錄數
341 if page_size isNone:342 data['records'] =len(result)343
344 returndata345
346 def get_count(self, wheres=''):347 """獲取指定條件記錄數量"""
348 ifwheres:349 wheres = 'where' +wheres350 sql = 'select count(1) as total from %(table_name)s %(wheres)s' %\351 {'table_name': self.__table_name, 'wheres': wheres}352 result =self.select(sql)353 #如果查詢存在記錄,則返回true
354 ifresult:355 return result[0].get('total')356 return0357
358 defget_sum(self, fields, wheres):359 """獲取指定條件記錄數量"""
360 sql = 'select sum(%(fields)s) as total from %(table_name)s where %(wheres)s' %\361 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}362 result =self.select(sql)363 #如果查詢存在記錄,則返回true
364 if result and result[0].get('total'):365 return result[0].get('total')366 return0367
368 defget_min(self, fields, wheres):369 """獲取該列記錄最小值"""
370 sql = 'select min(%(fields)s) as min from %(table_name)s where %(wheres)s' %\371 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}372 result =self.select(sql)373 #如果查詢存在記錄,則返回true
374 if result and result[0].get('min'):375 return result[0].get('min')376
377 defget_max(self, fields, wheres):378 """獲取該列記錄最大值"""
379 sql = 'select max(%(fields)s) as max from %(table_name)s where %(wheres)s' %\380 {'table_name': self.__table_name, 'wheres': wheres, 'fields': fields}381 result =self.select(sql)382 #如果查詢存在記錄,則返回true
383 if result and result[0].get('max'):384 return result[0].get('max')385
386 #####################################################################
387
388
389 #####################################################################
390 ### 緩存操作方法 ###
391
392 defget_cache_key(self, pk):393 """獲取緩存key值"""
394 return ''.join((self.__table_name, '_', str(pk)))395
396 def set_model_for_cache(self, pk, value, time=43200):397 """更新存儲在緩存中的數據庫記錄,緩存過期時間為12小時"""
398 #生成緩存key
399 key =self.get_cache_key(pk)400 #存儲到nosql緩存中
401 cache_helper.set(key, value, time)402
403 defget_model_for_cache(self, pk):404 """從緩存中讀取數據庫記錄"""
405 #生成緩存key
406 key =self.get_cache_key(pk)407 #從緩存中讀取數據庫記錄
408 result =cache_helper.get(key)409 #緩存中不存在記錄,則從數據庫獲取
410 if notresult:411 result =self.get_model_for_pk(pk)412 self.set_model_for_cache(pk, result)413 ifresult:414 returnresult415 else:416 return{}417
418 defget_value_for_cache(self, pk, column_name):419 """獲取指定記錄的字段值"""
420 returnself.get_model_for_cache(pk).get(column_name)421
422 defdel_model_for_cache(self, pk):423 """刪除緩存中指定數據"""
424 #生成緩存key
425 key =self.get_cache_key(pk)426 #log_helper.info(key)
427 #存儲到nosql緩存中
428 cache_helper.delete(key)429
430 defadd_relevance_cache_in_list(self, key):431 """將緩存名稱存儲到列表里————主要存儲與記錄變更關聯的"""
432 #從nosql中讀取全局緩存列表
433 cache_list = cache_helper.get(self.__cache_list)434 #判斷緩存列表是否有值,有則進行添加操作
435 ifcache_list:436 #判斷是否已存儲列表中,不存在則執行添加操作
437 if not key incache_list:438 cache_list.append(key)439 cache_helper.set(self.__cache_list, cache_list)440 #無則直接創建全局緩存列表,并存儲到nosql中
441 else:442 cache_list =[key]443 cache_helper.set(self.__cache_list, cache_list)444
445 defdel_relevance_cache(self):446 """刪除關聯緩存————將和數據表記錄關聯的,個性化緩存全部刪除"""
447 #從nosql中讀取全局緩存列表
448 cache_list = cache_helper.get(self.__cache_list)449 #清除已刪除緩存列表
450 cache_helper.delete(self.__cache_list)451 ifcache_list:452 #執行刪除操作
453 for cache incache_list:454 cache_helper.delete(cache)455
456 #####################################################################
View Code
版權聲明:本文原創發表于?博客園,作者為
python開發QQ群:669058475(本群已滿)、733466321(可以加2群)? ? 作者博客:http://www.cnblogs.com/EmptyFS/
總結
以上是生活随笔為你收集整理的python开发框架 代码生成_我的第一个python web开发框架(31)——定制ORM(七)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 现代软件工程系列 创新靠学分
- 下一篇: c# 获取路径的盘符_c#获取驱动器盘符