Python MySQL ORM QuickORM hacking

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: # coding: utf-8 # # Python MySQL ORM QuickORM hacking # 说明: # 以前仅仅是知道有ORM的存在,但是对ORM这个东西内部工作原理不是很清楚, # 这次正好需要用到,于是解读一个相对来说很简单的Python2 ORM的例子。
# 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):
    pass


class 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_cnt


class 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 = attrs


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

 

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1天前
|
SQL 关系型数据库 MySQL
Python进阶第二篇(Python与MySQL数据库)
Python进阶第二篇(Python与MySQL数据库)
|
7天前
|
关系型数据库 MySQL API
用Python一键艺龙酒店各个城市数据存入mysql
用Python一键艺龙酒店各个城市数据存入mysql
|
9天前
|
SQL 关系型数据库 MySQL
Python 操作 MySQL 数据库
Python 操作 MySQL 数据库
|
15天前
|
SQL 关系型数据库 数据库
17. Python 数据库操作之MySQL和SQLite实例
17. Python 数据库操作之MySQL和SQLite实例
47 2
|
20天前
|
SQL 关系型数据库 MySQL
Python 操作 MySQL 数据库
Python 操作 MySQL 数据库
|
Python 数据库管理
Python的ORM框架SQLAlchemy
API例子 import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String from sqlalchemy.orm import sessi
1856 0
|
1天前
|
开发者 Python
【干货】Python编程惯例
【干货】Python编程惯例
6 1
|
4天前
|
Shell Python
GitHub星标破千Star!Python游戏编程的初学者指南
Python 是一种高级程序设计语言,因其简洁、易读及可扩展性日渐成为程序设计领域备受推崇的语言。 目前的编程书籍大多分为两种类型。第一种,与其说是教编程的书,倒不如说是在教“游戏制作软件”,或教授使用一种呆板的语言,使得编程“简单”到不再是编程。而第二种,它们就像是教数学课一样教编程:所有的原理和概念都以小的应用程序的方式呈现给读者。
|
4天前
|
机器学习/深度学习 存储 自然语言处理
惊艳!老司机熬夜总结的Python高性能编程,高效、稳定、快速!
Python 语言是一种脚本语言,其应用领域非常广泛,包括数据分析、自然语言处理机器学习、科学计算、推荐系统构建等。 能够轻松实现和代码跑得够快之间的取舍却是一个世人皆知且令人惋惜的现象而这个问题其实是可以解决的。 有些人想要让顺序执行的过程跑得更快。有些人需要利用多核架构、集群,或者图形处理单元的优势来解决他们的问题。有些人需要可伸缩系统在保证可靠性的前提下酌情或根据资金多少处理更多或更少的工作。有些人意识到他们的编程技巧,通常是来自其他语言,可能不如别人的自然。