首页 > 代码库 > Python MySQL ORM QuickORM hacking

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 深圳 南山平山村 曾剑锋import MySQLdb## 作为和数据库中字段对应的域,同样也作为类属性存在# class Field(object):    passclass Expr(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 in kwargs.keys()]        self.where_expr = where  +  and .join(equations) if len(equations) > 0 else ‘‘    def update(self, **kwargs):        _keys = []        _params = []        # 筛选数据        for key, val in kwargs.iteritems():            if val is None or key not in self.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)        return Database.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)        return self    def select(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 in Database.execute(sql, self.params).fetchall():            # 获取传入的模板类型,这样就不用知道是什么类运行了select            inst = self.model()            # 获取一条信息中的值            for idx, f in enumerate(row):                setattr(inst, self.model.fields.keys()[idx], f)            yield inst    # 返回查询的数据统计总数    def count(self):        sql = select count(*) from %s %s; % (self.model.db_table, self.where_expr)        (row_cnt, ) = Database.execute(sql, self.params).fetchone()        return row_cntclass MetaModel(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():            if isinstance(val, Field):                fields[key] = val        cls.fields = fields        cls.attrs = attrsclass Model(object):    # 采用MetaModel来构建Model类    __metaclass__ = MetaModel    # 动态生成对应的sql语句,并执行对应的语句,要注意这里是self.__dict__获取的实例属性。    def save(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来查询    @classmethod    def where(cls, **kwargs):        return Expr(cls, kwargs)class Database(object):    autocommit = True    conn = None    db_config = {}    # 通过db_config字典数据设置连接数据库的值    @classmethod    def 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不通,那么重新连接,再返回。    @classmethod    def get_conn(cls):        if not cls.conn or not cls.conn.open:            cls.connect(**cls.db_config)        try:            cls.conn.ping()        except MySQLdb.OperationalError:            cls.connect(**cls.db_config)        return cls.conn    # 这里是直接执行sql语句,返回的是执行后的cursor    @classmethod    def execute(cls, *args):        cursor = cls.get_conn().cursor()        cursor.execute(*args)        return cursor    # 对象被垃圾回收机回收的时候调用    def __del__(self):        if self.conn and self.conn.open:            self.conn.close()# 执行原始sql语句def execute_raw_sql(sql, params=None):    return Database.execute(sql, params) if params else Database.execute(sql)

 

Python MySQL ORM QuickORM hacking