Python MySQL ORM QuickORM hacking

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
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)

 

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
6天前
|
关系型数据库 API 数据库
Python流行orm框架对比
Python中有多个流行的ORM框架,如SQLAlchemy、Django ORM、Peewee、Tortoise ORM、Pony ORM、SQLModel和GINO。每个框架各有特点,适用于不同的项目需求。SQLAlchemy功能强大且灵活,适合复杂项目;Django ORM与Django框架无缝集成,易用性强;Peewee轻量级且简单,适合小型项目;Tortoise ORM专为异步框架设计;Pony ORM查询语法直观;SQLModel结合Pydantic,适合FastAPI;GINO则适合异步环境开发。初学者推荐使用Django ORM或Peewee,因其易学易用。
|
1月前
|
关系型数据库 MySQL 数据库
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
273 15
|
3月前
|
SQL 关系型数据库 数据库
优化Web开发流程:Python ORM的优势与实现细节
【10月更文挑战第4天】在Web开发中,数据库操作至关重要,但直接编写SQL语句既繁琐又易错。对象关系映射(ORM)技术应运而生,让开发者以面向对象的方式操作数据库,显著提升了开发效率和代码可维护性。本文探讨Python ORM的优势及其实现细节,并通过Django ORM的示例展示其应用。ORM提供高级抽象层,简化数据库操作,提高代码可读性,并支持多种数据库后端,防止SQL注入。Django内置强大的ORM系统,通过定义模型、生成数据库表、插入和查询数据等步骤,展示了如何利用ORM简化复杂的数据库操作。
87 6
|
3月前
|
关系型数据库 MySQL 数据库
Mysql学习笔记(四):Python与Mysql交互--实现增删改查
如何使用Python与MySQL数据库进行交互,实现增删改查等基本操作的教程。
84 1
|
4月前
|
SQL 关系型数据库 MySQL
30天拿下Python之使用MySQL
30天拿下Python之使用MySQL
59 0
|
4月前
|
关系型数据库 MySQL 数据管理
pymysql:Python操作MySQL数据库的又一利器
pymysql:Python操作MySQL数据库的又一利器
44 0
|
4天前
|
缓存 关系型数据库 MySQL
【深入了解MySQL】优化查询性能与数据库设计的深度总结
本文详细介绍了MySQL查询优化和数据库设计技巧,涵盖基础优化、高级技巧及性能监控。
58 0
|
1月前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
61 3
|
1月前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
79 3
|
1月前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE 'log_%';`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
94 2