博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python MySQL ORM QuickORM hacking
阅读量:6228 次
发布时间:2019-06-21

本文共 4546 字,大约阅读时间需要 15 分钟。

# 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)

 

转载于:https://www.cnblogs.com/zengjfgit/p/5964442.html

你可能感兴趣的文章
2016 年总结
查看>>
将String转化成Stream,将Stream转换成String
查看>>
【工具使用系列】关于 MATLAB 遗传算法与直接搜索工具箱,你需要知道的事
查看>>
Kali-linux Arpspoof工具
查看>>
PDF文档页面如何重新排版?
查看>>
基于http协议使用protobuf进行前后端交互
查看>>
bash腳本編程之三 条件判断及算数运算
查看>>
php cookie
查看>>
linux下redis安装
查看>>
弃 Java 而使用 Kotlin 的你后悔了吗?| kotlin将会是最好的开发语言
查看>>
JavaScript 数据类型
查看>>
量子通信和大数据最有市场突破前景
查看>>
对‘初学者应该选择哪种编程语言’的回答——计算机达人成长之路(38)
查看>>
如何申请开通微信多客服功能
查看>>
Sr_C++_Engineer_(LBS_Engine@Global Map Dept.)
查看>>
非监督学习算法:异常检测
查看>>
jquery的checkbox,radio,select等方法总结
查看>>
Linux coredump
查看>>
Ubuntu 10.04安装水晶(Mercury)无线网卡驱动
查看>>
Myeclipes快捷键
查看>>