1. 程式人生 > >利用字典實現Python中簡單的ORM對映

利用字典實現Python中簡單的ORM對映

這週上班,寫了一個500多行的小指令碼,跟精準廣告投放有關,從線上的一些資料庫中提取必要的資料,經過一些邏輯判斷生成些新的資料,加一起放到自己這邊的資料庫裡

過程中也是複製貼上一路閃電帶火花地無腦弄出很多sql語句,寫完後覺得這程式碼要是改起來太蛋疼了,所以就想到了java裡的hibernate做的類與表之間的ORM對映

下面總結一下心得:

① 在連線資料庫的時候,設定cursorclass為MySQLdb.cursors.DictCursor是個不錯的選擇,當一個表有幾十個欄位的時候我才不想用數字來判斷是哪個欄位

import MySQLdb
import MySQLdb.cursors

conn = MySQLdb.connect(host="127.0.0.1", port=3306, user="root", passwd="root", db="test", cursorclass = MySQLdb.cursors.DictCursor)
cur = conn.cursor()

當然你也可以把這句設定寫在cursor的建立裡
conn = MySQLdb.connect(host="127.0.0.1", port=3306, user="root", passwd="root", db="test")
cur = conn.cursor(<span style="font-family: Arial, Helvetica, sans-serif;">cursorclass = MySQLdb.cursors.DictCursor</span>)

這樣的好處是,假如test庫中的user表裡有userid,username兩個欄位,在查詢之後你將得到一個字典dict,可以通過如下方式拿出他們
sql = 'SELECT * FROM user'
cur.execute(sql)
res = cur.fetchone()
print res['userid'], res['username']

當有多條記錄時,將返回一個字典的tuple,可以用for item in res的方式取到每個字典

② 在完成①的設定後,我發現,由於python很溫和,它不強求變數的型別,所以完全沒必要手動定義變數、設定預設值

你只需要在連線資料庫後,向每個表插入一次資料,得到的返回結果字典裡,已經包含了所有欄位名和他們的預設值

當然,別忘了刪掉它

# 預設uid,用於提取所有欄位
DEFAULT_USERID = -32767

# 獲取user初始值
def get_default_user():
	sql = 'INSERT INTO user(userid) values(%d)'%DEFAULT_USERID
	db.update(sql)
	sql = 'SELECT * FROM auto.auto_user WHERE uid = %d'%DEFAULT_UID
	global dct_user_default
	dct_user_default = db.queryone(sql)
	sql = 'DELETE FROM user WHERE userid = %d'%DEFAULT_UID
	db.update(sql)

其中db是一個數據庫操作的類,管了各種execute和commit,不要在意

執行該方法,就會獲得一個全域性變數dct_user_default,它是一個包含所有欄位名、預設值的字典,除了userid是你定義的預設值

然後當new……好吧沒有new,建立一個類物件時,deepcopy它一份,把userid之類的主鍵改掉即可

# user對應類
class obj_user(object):
	def __init__(self):
		# 獲取預設欄位與值
		self.val = copy.deepcopy(dct_user_default)
		# 設定主鍵userid
		self.set('userid',userid)

	def get(self,key):
		if self.val.has_key(key):
			return self.val[key]
		else:
			return None

	def set(self, key, value):
		self.val[key] = value

裡面的get、set方法,可以讓你感受到用Java的快感【別鬧

③ 接著,就是怎樣將一個user類提交給資料庫更新對應的資料了

正常來說這樣的方法應該交給資料庫操作類,而不是該類本身的行為……大概吧,不過我就愛寫這你管我

	# 插入使用者資訊			
	def insert_user(self):
		# key_str是所有的欄位名,以逗號分隔
		key_str = ''
		# val_str是所有的佔位符,以逗號分隔
		val_str = ''
		# param是self.val中對應的值
		param = []
		for key in self.val:
			key_str += key + ","
			val_str += "%s,"
			param.append(self.val[key])
			sql = 'INSERT INTO user(%s) values(%s)'%(key_str[:-1],val_str[:-1])
		db.update(sql,param)
這樣就會在INSERT INTO auto.auto_user(%s)的%s部分自動填入所有的欄位名,在valus(%s)部分填入足夠的佔位符

這是一個構造sql語句的過程,好處是你不需要勞心地去一個個手動填名字,排值的位置

update之類的語句也是同理,拼set後面的語句,欄位名1=值2,欄位名1=值2,...這樣的

④ 完成③之後再回頭看②,會發現一件事,dct_user_default根本就是多餘的……

為什麼?比如下面的程式碼:

user = obj_user('53723')
user.set('username','naoe')
user.insert_user()

你可以自由地set多個欄位的值,這個時候還是得知道欄位名的

set方法實際就是在字典裡查詢key,設定對應的value,沒有這個key的話,會自動新建一個

而實際在insert或者update的時候,我們都是以指定欄位名的方式操作的,指定哪些就更新哪些,其他欄位會自動填入預設值

所以……其實並不需要get_default_user,當然作為一個獲取欄位名和預設值的辦法,我覺得它還是挺棒的

總得來說,最花時間的地方還是理邏輯→提出不合理的地方→討論→改資料庫表的設計→改程式碼→理邏輯……這樣一個迴圈

以及虐的我快要哭著找媽媽的編碼問題,下次貼上來

其實這周挺閒的,寫了個從視訊生成終端下面的字串動畫的小指令碼,就沒幾行程式碼,下次理一理也放上來

還想寫個螢幕錄製gif的,嘛,有空再說