orm python mysql_Python MySQL ORM QuickORM hacking

#coding: utf-8

#

#Python MySQL ORM QuickORM hacking#说明:#以前仅仅是知道有ORM的存在,但是对ORM这个东西内部工作原理不是很清楚,#这次正好需要用到,于是解读一个相对来说很简单的Python2 ORM的例子。#

#参考源码:#A simple ORM provides elegant API for Python-MySQL operation#https://github.com/2shou/QuickORM#

#2016-10-15 深圳 南山平山村 曾剑锋

importMySQLdb#

#作为和数据库中字段对应的域,同样也作为类属性存在#

classField(object):pass

classExpr(object):#合成where查询部分

def __init__(self, model, kwargs):

self.model=model#How to deal with a non-dict parameter?

#提取键值对的value部分

self.params =kwargs.values()#提取键值对的key部分,并合成替代字符串

equations = [key + '= %s' for key inkwargs.keys()]

self.where_expr= 'where' + 'and'.join(equations) if len(equations) > 0 else ''

def update(self, **kwargs):

_keys=[]

_params=[]#筛选数据

for key, val inkwargs.iteritems():if val is None or key not inself.model.fields:continue_keys.append(key)

_params.append(val)#和__init__中的键值对的values数据联合

_params.extend(self.params)#合成查询语句

sql = 'update %s set %s %s;' %(

self.model.db_table,','.join([key + '= %s' for key in_keys]), self.where_expr)returnDatabase.execute(sql, _params)def limit(self, rows, offset=None):#合成limit数据,这里就是合成想从那一行开始取数据,取多少数据

self.where_expr += 'limit %s%s' %('%s,' % offset if offset is not None else '', rows)returnselfdefselect(self):#合成查询语句,需要查询的字段,表明,条件

sql = 'select %s from %s %s;' % (','.join(self.model.fields.keys()), self.model.db_table, self.where_expr)#取出所有的数据,这里使用了yield,使得select可以被for in语法再次迭代从而获取到值

for row inDatabase.execute(sql, self.params).fetchall():#获取传入的模板类型,这样就不用知道是什么类运行了select

inst =self.model()#获取一条信息中的值

for idx, f inenumerate(row):

setattr(inst, self.model.fields.keys()[idx], f)yieldinst#返回查询的数据统计总数

defcount(self):

sql= 'select count(*) from %s %s;' %(self.model.db_table, self.where_expr)

(row_cnt, )=Database.execute(sql, self.params).fetchone()returnrow_cntclassMetaModel(type):

db_table=None

fields={}def __init__(cls, name, bases, attrs):

super(MetaModel, cls).__init__(name, bases, attrs)

fields={}#从类所有的属性中提取出类属性,和数据库中的字段对应,这里更多的给Expr类使用。

for key, val in cls.__dict__.iteritems():ifisinstance(val, Field):

fields[key]=val

cls.fields=fields

cls.attrs=attrsclassModel(object):#采用MetaModel来构建Model类

__metaclass__ =MetaModel#动态生成对应的sql语句,并执行对应的语句,要注意这里是self.__dict__获取的实例属性。

defsave(self):

insert= 'insert ignore into %s(%s) values (%s);' %(

self.db_table,','.join(self.__dict__.keys()), ','.join(['%s'] * len(self.__dict__)))return Database.execute(insert, self.__dict__.values())#使用where来查询

@classmethoddef where(cls, **kwargs):returnExpr(cls, kwargs)classDatabase(object):

autocommit=True

conn=None

db_config={}#通过db_config字典数据设置连接数据库的值

@classmethoddef connect(cls, **db_config):

cls.conn= MySQLdb.connect(host=db_config.get('host', 'localhost'), port=int(db_config.get('port', 3306)),

user=db_config.get('user', 'root'), passwd=db_config.get('password', ''),

db=db_config.get('database', 'test'), charset=db_config.get('charset', 'utf8'))

cls.conn.autocommit(cls.autocommit)

cls.db_config.update(db_config)#这里是连接数据库,里面有一些策略,譬如:

#1. 如果没有连接数据库,那么就连接数据库;

#2. 如果连接了数据库,那么测试是否可ping通再返回连接;

#3. 如果ping不通,那么重新连接,再返回。

@classmethoddefget_conn(cls):if not cls.conn or notcls.conn.open:

cls.connect(**cls.db_config)try:

cls.conn.ping()exceptMySQLdb.OperationalError:

cls.connect(**cls.db_config)returncls.conn#这里是直接执行sql语句,返回的是执行后的cursor

@classmethoddef execute(cls, *args):

cursor=cls.get_conn().cursor()

cursor.execute(*args)returncursor#对象被垃圾回收机回收的时候调用

def __del__(self):if self.conn andself.conn.open:

self.conn.close()#执行原始sql语句

def execute_raw_sql(sql, params=None):return Database.execute(sql, params) if params else Database.execute(sql)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值