利用字典实现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(cursorclass = MySQLdb.cursors.DictCursor)

这样的好处是,假如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的,嘛,有空再说

你可能感兴趣的:(Python)