iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >用 Python 元类的特性实现 ORM 框架
  • 175
分享到

用 Python 元类的特性实现 ORM 框架

python元类python实现orm框架 2022-06-02 22:06:18 175人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录ORM是什么实现ORM中的insert功能完善对数据类型的检测抽取到基类中添加数据库驱动执行sql语句添加数据库驱动执行sql语句测试功能准备数据库创建模型类测试源代码ORM是什么 O是 object,也就 类

目录
  • ORM是什么
  • 实现ORM中的insert功能
  • 完善对数据类型的检测
  • 抽取到基类中
  • 添加数据库驱动执行sql语句
  • 添加数据库驱动执行sql语句
  • 测试功能
    • 准备数据库
    • 创建模型类测试
  • 源代码

    ORM是什么

    O是 object,也就 类对象 的意思,R是 relation,翻译成中文是 关系,也就是关系数据库中 数据表 的意思,M是 mapping,是映射的意思。在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据。ORM框架还有一个功能,它可以根据我们设计的类自动帮我们生成数据库中的表,省去了我们自己建表的过程。

    一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应 Mysql 语句。

    Django 中就内嵌了一个 ORM 框架,不需要直接面向数据库编程,而是定义模型类,通过模型类和对象完成数据表的增删改查操作。还有第三方库 sqlalchemy 都是 ORM框架。

    先看看我们大致要实现什么功能

    
    class User(父类省略):
        uid = ('uid', "int unsigned")
        name = ('username', "varchar(30)")
        email = ('email', "varchar(30)")
        passWord = ('password', "varchar(30)")
        ...省略...
    
    
    user = User(uid=123, name='hui', email='huidbk@163.com', password='123456')
    user.save()
    
    # 对应如下sql语句
    # insert into User (uid,username,email,password) values (123,hui,huidbk@163.com,123456)
    

    所谓的 ORM 就是让开发者在操作数据库的时候,能够像操作对象时通过xxxx.属性=yyyy一样简单,这是开发ORM的初衷。

    实现ORM中的insert功能

    通过 python 中 元类 简单实现 ORM 中的 insert 功能

    
    # !/usr/bin/python3
    # -*- coding: utf-8 -*-
    # @Author: Hui
    # @Desc: { 利用Python元类简单实现ORM框架的Insert插入功能 }
    # @Date: 2021/05/17 17:02
    
    
    class ModelMetaclass(type):
        """数据表模型元类"""
    
        def __new__(mcs, cls_name, bases, attrs):
    
            print(f'cls_name -> {cls_name}')    # 类名
            print(f'bases -> {bases}')          # 继承类
            print(f'attrs -> {attrs}')          # 类中所有属性
            print()
    
            # 数据表对应关系字典
            mappings = dict()
    
            # 过滤出对应数据表的字段属性
            for k, v in attrs.items():
                # 判断是否是指定的StringField或者IntegerField的实例对象
                # 这里就简单判断字段是元组
                if isinstance(v, tuple):
                    print('Found mapping: %s ==> %s' % (k, v))
                    mappings[k] = v
    
            # 删除这些已经在字典中存储的字段属性
            for k in mappings.keys():
                attrs.pop(k)
    
            # 将之前的uid/name/email/password以及对应的对象引用、类名字
            # 用其他类属性名称保存
            attrs['__mappings__'] = mappings  # 保存属性和列的映射关系
            attrs['__table__'] = cls_name     # 假设表名和类名一致
            return type.__new__(mcs, cls_name, bases, attrs)
    
    
    class User(metaclass=ModelMetaclass):
        """用户模型类"""
    	# 类属性名    表字段    表字段类型
        uid =      ('uid', 'int unsigned')
        name =     ('username', 'varchar(30)')
        email =    ('email', 'varchar(30)')
        password = ('password', 'varchar(30)')
    
        def __init__(self, **kwargs):
            for name, value in kwargs.items():
                setattr(self, name, value)
    
        def save(self):
            fields = []
            args = []
            for k, v in self.__mappings__.items():
                fields.append(v[0])
                args.append(getattr(self, k, None))
    
            # 表名
            table_name = self.__table__
            # 数据表中的字段
            fields = ','.join(fields)
            # 待插入的数据
            args = ','.join([str(i) for i in args])
            
            # 生成sql语句
            sql = f"""insert into {table_name} ({fields}) values ({args})"""
            print(f'SQL: {sql}')
    
    
    def main():
        user = User(uid=123, name='hui', email='huidbk@163.com', password='123456')
        user.save()
    
    
    if __name__ == '__main__':
        main()
    
    

    当 User 指定元类之后,uid、name、email、password 类属性将不在类中,而是在 __mappings__ 属性指定的字典中存储。 User 类的这些属性将转变为如下

    
    __mappings__ = {
        "uid": ('uid', "int unsigned")
        "name": ('username', "varchar(30)")
        "email": ('email', "varchar(30)")
        "password": ('password', "varchar(30)")
    }
    __table__ = "User"
    

    执行的效果如下:

    
    cls_name -> User
    bases -> ()
    attrs -> {
        '__module__': '__main__', '__qualname__': 'User', '__doc__': '用户模型类', 
        'uid': ('uid', 'int unsigned'), 
        'name': ('username', 'varchar(30)'), 
        'email': ('email', 'varchar(30)'), 
        'password': ('password', 'varchar(30)'), 
        '__init__': <function User.__init__ at 0x0000026D520C1048>, 
        'save': <function User.save at 0x0000026D520C10D8>
    }
    
    Found mapping: uid ==> ('uid', 'int unsigned')
    Found mapping: name ==> ('username', 'varchar(30)')
    Found mapping: email ==> ('email', 'varchar(30)')
    Found mapping: password ==> ('password', 'varchar(30)')
    
    SQL: insert into User (uid,username,email,password) values (123,hui,huidbk@163.com,123456)
    

    完善对数据类型的检测

    上面转成的 sql 语句如下:

    
    insert into User (uid,username,email,password) values (12345,hui,huidbk@163.com,123456)
    

    发现没有,在 sql 语句中字符串类型没有没有引号 ''

    正确的 sql 语句应该是:

    
    insert into User (uid,username,email,password) values (123, 'hui', 'huidbk@163.com', '123456')
    

    因此修改 User 类完善数据类型的检测

    
    class ModelMetaclass(type):
        # 此处和上文一样, 故省略....
        pass
        
    class User(metaclass=ModelMetaclass):
        """用户模型类"""
    
        uid = ('uid', "int unsigned")
        name = ('username', "varchar(30)")
        email = ('email', "varchar(30)")
        password = ('password', "varchar(30)")
    
        def __init__(self, **kwargs):
            for name, value in kwargs.items():
                setattr(self, name, value)
    
        # 在这里完善数据类型检测
        def save(self):
            fields = []
            args = []
            for k, v in self.__mappings__.items():
                fields.append(v[0])
                args.append(getattr(self, k, None))
    
            # 把参数数据类型对应数据表的字段类型
            args_temp = list()
            for temp in args:
                if isinstance(temp, int):
                    args_temp.append(str(temp))
                elif isinstance(temp, str):
                    args_temp.append(f"'{temp}'")
    
            # 表名
            table_name = self.__table__
            # 数据表中的字段
            fields = ','.join(fields)
            # 待插入的数据
            args = ','.join(args_temp)
    
            # 生成sql语句
            sql = f"""insert into {table_name} ({fields}) values ({args})"""
            print(f'SQL: {sql}')
    
    
    def main():
        user = User(uid=123, name='hui', email='huidbk@163.com', password='123456')
        user.save()
    
    
    if __name__ == '__main__':
        main()
    
    

    运行效果如下:

    
    cls_name -> User
    bases -> ()
    attrs -> {
        '__module__': '__main__', '__qualname__': 'User', '__doc__': '用户模型类', 
        'uid': ('uid', 'int unsigned'), 
        'name': ('username', 'varchar(30)'), 
        'email': ('email', 'varchar(30)'), 
        'password': ('password', 'varchar(30)'), 
        '__init__': <function User.__init__ at 0x0000026D520C1048>, 
        'save': <function User.save at 0x0000026D520C10D8>
    }
    
    Found mapping: uid ==> ('uid', 'int unsigned')
    Found mapping: name ==> ('username', 'varchar(30)')
    Found mapping: email ==> ('email', 'varchar(30)')
    Found mapping: password ==> ('password', 'varchar(30)')
        
    SQL: insert into User (uid,username,email,password) values(123,'hui','huidbk@163.com','123456')
    

    抽取到基类中

    
    # !/usr/bin/python3
    # -*- coding: utf-8 -*-
    # @Author: Hui
    # @Desc: { 利用Python元类实现ORM框架的Insert插入功能 }
    # @Date: 2021/05/17 17:02
    
    
    class ModelMetaclass(type):
        """数据表模型元类"""
    
        def __new__(mcs, cls_name, bases, attrs):
    
            print(f'cls_name -> {cls_name}')  # 类名
            print(f'bases -> {bases}')  # 继承类
            print(f'attrs -> {attrs}')  # 类中所有属性
            print()
    
            # 数据表对应关系字典
            mappings = dict()
    
            # 过滤出对应数据表的字段属性
            for k, v in attrs.items():
                # 判断是否是对应数据表的字段属性, 因为attrs中包含所有的类属性
                # 这里就简单判断字段是元组
                if isinstance(v, tuple):
                    print('Found mapping: %s ==> %s' % (k, v))
                    mappings[k] = v
    
            # 删除这些已经在字典中存储的字段属性
            for k in mappings.keys():
                attrs.pop(k)
    
            # 将之前的uid/name/email/password以及对应的对象引用、类名字
            # 用其他类属性名称保存
            attrs['__mappings__'] = mappings  # 保存属性和列的映射关系
            attrs['__table__'] = cls_name  # 假设表名和类名一致
            return type.__new__(mcs, cls_name, bases, attrs)
    
    
    class Model(object, metaclass=ModelMetaclass):
        """数据表模型基类"""
    
        def __init__(self, **kwargs):
            for name, value in kwargs.items():
                setattr(self, name, value)
    
        def save(self):
            fields = []
            args = []
            for k, v in self.__mappings__.items():
                fields.append(v[0])
                args.append(getattr(self, k, None))
    
            # 把参数数据类型对应数据表的字段类型
            args_temp = list()
            for temp in args:
                if isinstance(temp, int):
                    args_temp.append(str(temp))
                elif isinstance(temp, str):
                    args_temp.append(f"'{temp}'")
    
            # 表名
            table_name = self.__table__
            # 数据表中的字段
            fields = ','.join(fields)
            # 待插入的数据
            args = ','.join(args_temp)
    
            # 生成sql语句
            sql = f"""insert into {table_name} ({fields}) values ({args})"""
            print(f'SQL: {sql}')
    
            # 执行sql语句
            # ...
    
    
    class User(Model):
        """用户表模型类"""
    
        uid = ('uid', "int unsigned")
        name = ('username', "varchar(30)")
        email = ('email', "varchar(30)")
        password = ('password', "varchar(30)")
    
    
    def main():
        user = User(uid=123, name='hui', email='huidbk@163.com', password='123456')
        user.save()
    
    
    if __name__ == '__main__':
        main()
    
    

    添加数据库驱动执行sql语句

    这里我们使用 pymysql 数据库驱动,来执行 sql 语句

    在 Model 类中新增一个 get_connection 的静态方法用于获取数据库连接

    
    import pymysql
    
    
    class Model(object, metaclass=ModelMetaclass):
        """数据表模型基类"""
    
        def __init__(self, **kwargs):
            for name, value in kwargs.items():
                setattr(self, name, value)
    
        @staticmethod
        def get_connection():
            """
            获取数据库连接与数据游标
            :return: conn, cursor
            """
            conn = pymysql.connect(
                database='testdb',
                host='localhost',
                port=3306,
                user='root',
                password='123456'
            )
            return conn, conn.cursor()
    
        def save(self):
            fields = []
            args = []
            for k, v in self.__mappings__.items():
                fields.append(v[0])
                args.append(getattr(self, k, None))
    
            # 把参数数据类型对应数据表的字段类型
            args_temp = list()
            for temp in args:
                if isinstance(temp, int):
                    args_temp.append(str(temp))
                elif isinstance(temp, str):
                    args_temp.append(f"'{temp}'")
    
            # 表名
            table_name = self.__table__
            # 数据表中的字段
            fields = ','.join(fields)
            # 待插入的数据
            args = ','.join(args_temp)
    
            # 生成sql语句
            sql = f"""insert into {table_name} ({fields}) values ({args})"""
            print(f'SQL: {sql}')
    
            # 执行sql语句
            conn, cursor = self.get_connection()
            ret = cursor.execute(sql)
            print(ret)
            conn.commit()
            cursor.close()
            conn.close()
            
    

    添加数据库驱动执行sql语句

    这里我们使用 pymysql 数据库驱动,来执行 sql 语句

    在 Model 类中新增一个 get_connection 的静态方法用于获取数据库连接

    
    import pymysql
    
    
    class Model(object, metaclass=ModelMetaclass):
        """数据表模型基类"""
    
        def __init__(self, **kwargs):
            for name, value in kwargs.items():
                setattr(self, name, value)
    
        @staticmethod
        def get_connection():
            """
            获取数据库连接与数据游标
            :return: conn, cursor
            """
            conn = pymysql.connect(
                database='testdb',
                host='localhost',
                port=3306,
                user='root',
                password='123456'
            )
            return conn, conn.cursor()
    
        def save(self):
            fields = []
            args = []
            for k, v in self.__mappings__.items():
                fields.append(v[0])
                args.append(getattr(self, k, None))
    
            # 把参数数据类型对应数据表的字段类型
            args_temp = list()
            for temp in args:
                if isinstance(temp, int):
                    args_temp.append(str(temp))
                elif isinstance(temp, str):
                    args_temp.append(f"'{temp}'")
    
            # 表名
            table_name = self.__table__
            # 数据表中的字段
            fields = ','.join(fields)
            # 待插入的数据
            args = ','.join(args_temp)
    
            # 生成sql语句
            sql = f"""insert into {table_name} ({fields}) values ({args})"""
            print(f'SQL: {sql}')
    
            # 执行sql语句
            conn, cursor = self.get_connection()
            ret = cursor.execute(sql)
            print(ret)
            conn.commit()
            cursor.close()
            conn.close()
            
    

    测试功能

    准备数据库

    先准备数据库 testdb 和 user 数据表

    
    create database testdb charset=utf8;
    
    use testdb;
    
    create table user(
    	uid int unsigned auto_increment primary key,
    	username varchar(30) not null,
    	email varchar(30),
    	password varchar(30) not null
    );
    

    user 表结构如下

    
    +----------+------------------+------+-----+---------+----------------+
    | Field    | Type             | Null | Key | Default | Extra          |
    +----------+------------------+------+-----+---------+----------------+
    | uid      | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
    | username | varchar(30)      | NO   |     | NULL    |                |
    | email    | varchar(30)      | YES  |     | NULL    |                |
    | password | varchar(30)      | NO   |     | NULL    |                |
    +----------+------------------+------+-----+---------+----------------+
    

    创建模型类测试

    
    class User(Model):
        """用户表模型类"""
    
        uid = ('uid', "int unsigned")
        name = ('username', "varchar(30)")
        email = ('email', "varchar(30)")
        password = ('password', "varchar(30)")
    
    
    def main():
        user = User(uid=1, name='hui', email='huidbk@163.com', password='123456')
        user.save()
    
        for i in range(2, 10):
            user = User(
                uid=i,
                name=f'name{i}',
                email=f'huidbk@16{i}.com',
                password=f'12345{i}'
            )
            user.save()
        
    
    if __name__ == '__main__':
        main()
        
    

    查看数据库 user 表数据

    
    mysql> select * from user;
    +-----+----------+----------------+----------+
    | uid | username | email          | password |
    +-----+----------+----------------+----------+
    |   1 | hui      | huidbk@163.com | 123456   |
    |   2 | name2    | huidbk@162.com | 123452   |
    |   3 | name3    | huidbk@163.com | 123453   |
    |   4 | name4    | huidbk@164.com | 123454   |
    |   5 | name5    | huidbk@165.com | 123455   |
    |   6 | name6    | huidbk@166.com | 123456   |
    |   7 | name7    | huidbk@167.com | 123457   |
    |   8 | name8    | huidbk@168.com | 123458   |
    |   9 | name9    | huidbk@169.com | 123459   |
    +-----+----------+----------------+----------+
    9 rows in set (0.00 sec)
    

    源代码

    源代码已上传到 gitee PythonKnowledge: Python知识宝库,欢迎大家来访。

    以上就是用 Python 元类的特性实现 ORM 框架的详细内容,更多关于Python 实现 ORM 框架的资料请关注编程网其它相关文章!

    --结束END--

    本文标题: 用 Python 元类的特性实现 ORM 框架

    本文链接: https://www.lsjlt.com/news/10690.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • 如何使用Python元类特性实现ORM框架
      这篇文章主要介绍了如何使用Python元类特性实现ORM框架,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。ORM是什么O是 object,也就 类对象 的意思,R是 rela...
      99+
      2023-06-15
    • Python元类编程实现一个简单的ORM
      目录概述效果步骤结束语完整代码概述 什么是ORM    ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的...
      99+
      2023-03-06
      Python元类编程ORM Python ORM
    • Python ORM框架中的SQLAlchemy怎么用
      小编给大家分享一下Python ORM框架中的SQLAlchemy怎么用,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、SQLAlchemy 介绍1.1 ORM 的概念ORM全称Object Relationa...
      99+
      2023-06-29
    • 怎么使用Python元类编程实现一个简单的ORM
      这篇文章主要讲解了“怎么使用Python元类编程实现一个简单的ORM”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用Python元类编程实现一个简单的ORM”吧!概述什么是ORM   ...
      99+
      2023-07-05
    • python中ORM框架的作用是什么
      python中ORM框架的作用是什么?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。python有哪些常用库python常用的库:1.requesuts;2.scrapy;3...
      99+
      2023-06-14
    • Python ORM框架之SQLAlchemy 的基础用法
      目录一、SQLAlchemy 介绍1.1 ORM 的概念1.2 SQLAlchemy介绍1.3 架构1.4 异步1.5 安装二、SQLAlchemy 快速入门2.1 创建配置(可选)...
      99+
      2024-04-02
    • 轻量级ORM框架Dapper应用之实现DTO
      一、什么是DTO 先来看看百度百科的解释: 数据传输对象(DTO)(Data Transfer Object),是一种设计模式之间传输数据的软件应用系统。数据传输目标往往是数据访问对...
      99+
      2024-04-02
    • python利用元类和描述器实现ORM模型的详细步骤
      ORM模型: ORM模型对于后端开发来说肯定是不陌生的,包括很多后端框架比如django,现在都自带这个模型了 ORM(Object Relational Mapping)对象关系映...
      99+
      2024-04-02
    • 轻量级ORM框架Dapper应用之实现CURD操作
      在上一篇文章中,讲解了如何安装Dapper,这篇文章中将会讲解如何使用Dapper使用CURD操作。 例子中使用到的实体类定义如下: using System; using Syst...
      99+
      2024-04-02
    • 轻量级ORM框架Dapper应用之实现Join操作
      在这篇文章中,讲解如何使用Dapper使用Inner join的操作 1、新创建两张表:Users表和Product表 Users表定义如下: CREATE TABLE [dbo]....
      99+
      2024-04-02
    • 轻量级ORM框架Dapper应用之实现In操作
      IN 操作符允许我们在 WHERE 子句中规定多个值。 本篇文章中,还是使用和上篇文章中同样的实体类和数据库,Dapper使用in操作符的代码如下: using System...
      99+
      2024-04-02
    • 轻量级ORM框架Dapper应用实现In操作的方法
      本篇内容介绍了“轻量级ORM框架Dapper应用实现In操作的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Dapper使用in操作符的...
      99+
      2023-06-29
    • 使用 Python ORM 实现高效的数据持久性
      对象关系映射(ORM)是一种技术,它允许在面向对象编程语言和关系数据库之间建立桥梁。使用 Python ORM 可以显著简化数据持久性操作,从而提高应用程序的开发效率和可维护性。 优势 使用 Python ORM 具有以下优势: 减少样...
      99+
      2024-03-15
      ORM
    • Python ORM数据库框架Sqlalchemy的使用教程详解
      目录概念和数据类型安装连接创建数据库表类(模型)生成数据库表会话增删改查增查改删执行裸sqlwith关闭会话sql建造者模式封装的工具数据库配置文件database.properti...
      99+
      2024-04-02
    • 使用Python实现简单的爬虫框架
      目录一、请求网页二、解析 HTML三、构建爬虫框架爬虫是一种自动获取网页内容的程序,它可以帮助我们从网络上快速收集大量信息。在本文中,我们将学习如何使用 Python 编写一个简单的...
      99+
      2023-05-19
      Python如何实现爬虫框架 Python爬虫框架 Python爬虫
    • 学习不同canvas框架:了解各种canvas框架的特性与使用场景
      深入研究canvas框架:掌握多种canvas框架的特点与应用场景,需要具体代码示例 近年来,Web前端开发的重要领域之一是图像处理和动画效果。为了实现这些效果,开发人员通常使用HTML5的canvas元素。canvas元素提供...
      99+
      2024-01-17
      Canvas 框架 应用场景
    • git框架如何优化Python数据类型的性能?
      Git框架如何优化Python数据类型的性能? 在Python编程中,数据类型是非常重要的。它们可以帮助我们更好地组织和操作数据。然而,在处理大量数据时,Python的解释器可能会变得缓慢。在这种情况下,我们需要一些优化方法来加快Pytho...
      99+
      2023-07-18
      数据类型 git 框架
    • python实现一个简单的web应用框架
      目录引言写应用框架需要写底层服务器么uwsgi基本使用安装uwsgi配置uwsgiuwsgi常用配置uwsgi启服和停服启动一个demo写一个简单的web应用框架总结引言 本篇文章所...
      99+
      2023-05-18
      python web应用框架 python web
    • Spring 框架中数据类型的特点和应用场景
      Spring 框架中数据类型的特点和应用场景 Spring 是一个轻量级的开源框架,它提供了一个基于依赖注入(DI)和面向切面编程(AOP)的环境,用于开发企业级应用程序。Spring 框架中的数据类型是其核心组件之一,本文将介绍 Spri...
      99+
      2023-07-04
      数据类型 spring apache
    • 使用Django框架中ORM系统实现对数据库数据增删改查
      目录1.数据的增删改查----------增加数据在视图函数中导入User模型类,然后使用下面的方法添加数据:2.数据的增删改查----------查找数据这时在定义模型类时定义的_...
      99+
      2024-04-02
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作