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

如何使用Python元类特性实现ORM框架

2023-06-15 04:06:20 411人浏览 薄情痞子

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

摘要

这篇文章主要介绍了如何使用python元类特性实现ORM框架,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。ORM是什么O是 object,也就 类对象 的意思,R是 rela

这篇文章主要介绍了如何使用python元类特性实现ORM框架,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

ORM是什么

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

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

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

如何使用Python元类特性实现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:02class 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 -> Userbases -> ()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 -> Userbases -> ()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:02class 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 pymysqlclass 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 pymysqlclass 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)

python的五大特点是什么

python的五大特点:1.简单易学,开发程序时,专注的是解决问题,而不是搞明白语言本身。2.面向对象,与其他主要的语言如c++和Java相比, Python以一种非常强大又简单的方式实现面向对象编程。3.可移植性,Python程序无需修改就可以在各种平台上运行。4.解释性,Python语言写的程序不需要编译成二进制代码,可以直接从源代码运行程序。5.开源,Python是 FLOSS(自由/开放源码软件)之一。

感谢你能够认真阅读完这篇文章,希望小编分享的“如何使用Python元类特性实现ORM框架”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网Python频道,更多相关知识等着你来学习!

--结束END--

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

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

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

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

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

下载Word文档
猜你喜欢
  • 如何使用Python元类特性实现ORM框架
    这篇文章主要介绍了如何使用Python元类特性实现ORM框架,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。ORM是什么O是 object,也就 类对象 的意思,R是 rela...
    99+
    2023-06-15
  • 如何使用C++的ORM框架QxORM
    这篇文章主要讲解了“如何使用C++的ORM框架QxORM”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用C++的ORM框架QxORM”吧!QxORM中,我们用的最多的无非是这两点官方表...
    99+
    2023-07-02
  • c# 如何自己实现一个ORM框架
    目录0. 前言1. ORM2. 设计3. 实现4. 总结0. 前言 在之前的几篇内容中,我们了解了如何通过ADO.NET 访问数据库,如何修改、新增数据。如何通过DataSet和D...
    99+
    2024-04-02
  • 怎么使用Python元类编程实现一个简单的ORM
    这篇文章主要讲解了“怎么使用Python元类编程实现一个简单的ORM”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么使用Python元类编程实现一个简单的ORM”吧!概述什么是ORM   ...
    99+
    2023-07-05
  • 如何使用Python元类实现单例模式
    这篇文章主要介绍了如何使用Python元类实现单例模式,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。元类实现:class MetaClass(type): ...
    99+
    2023-06-17
  • gtest单元测试框架如何使用
    使用gtest单元测试框架,需要按照以下步骤: 下载并安装gtest框架:可以从https://github.com/googl...
    99+
    2023-10-21
    gtest
  • 使用 Python ORM 实现高效的数据持久性
    对象关系映射(ORM)是一种技术,它允许在面向对象编程语言和关系数据库之间建立桥梁。使用 Python ORM 可以显著简化数据持久性操作,从而提高应用程序的开发效率和可维护性。 优势 使用 Python ORM 具有以下优势: 减少样...
    99+
    2024-03-15
    ORM
  • 如何使用Python来提高Spring框架的性能?
    好的,下面是文章的内容: Spring框架是一个非常流行的Java企业级应用程序开发框架,它提供了丰富的特性和功能,让开发者可以快速构建高效的应用程序。然而,在处理大量数据时,Spring框架的性能可能会受到影响。本文将介绍如何使用Pyth...
    99+
    2023-09-16
    bash spring load
  • python如何使用socket实现TCP协议长连接框架
    这篇文章主要介绍了python如何使用socket实现TCP协议长连接框架,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。分析多了协议就会发现,很多的应用,特别是游戏类和IM类...
    99+
    2023-06-29
  • python利用元类和描述器实现ORM模型的详细步骤
    ORM模型: ORM模型对于后端开发来说肯定是不陌生的,包括很多后端框架比如django,现在都自带这个模型了 ORM(Object Relational Mapping)对象关系映...
    99+
    2024-04-02
  • 如何使用 Python 框架的 HTTP API 实现数据交换?
    当今互联网时代,数据交换是各种应用程序之间必不可少的一部分。Python框架的HTTP API是一种常用的数据交换方式,本文将介绍如何使用Python框架的HTTP API实现数据交换。 一、什么是HTTP API? HTTP API是一种...
    99+
    2023-10-06
    框架 api http
  • Python中sqlalchemy框架如何使用
    今天就跟大家聊聊有关Python中sqlalchemy框架如何使用,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。安装安装#进入虚拟环境#执行./python3 -m&nbs...
    99+
    2023-06-20
  • python中如何使用Django框架
    这篇文章将为大家详细讲解有关python中如何使用Django框架,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。第一步:项目的创建与运行第一次使用 Django ,那么你必须要照顾一些初始设...
    99+
    2023-06-20
  • python元类编程如何使用
    本文小编为大家详细介绍“python元类编程如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“python元类编程如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。1.1.propety动态属性在面向对...
    99+
    2023-07-05
  • 如何使用 Python 框架来实现自然语言处理?
    自然语言处理(Natural Language Processing,简称NLP)是人工智能领域的一个重要分支,它的目标是让计算机能够理解人类的自然语言,例如中文、英文等。Python是一种流行的编程语言,它提供了许多工具和库,可以帮助我...
    99+
    2023-10-08
    框架 自然语言处理 spring
  • 如何在Python中使用元类
    如何在Python中使用元类?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。python的五大特点是什么python的五大特点:1.简单易学,开发程序时,专注的是...
    99+
    2023-06-14
  • git框架如何优化Python数据类型的性能?
    Git框架如何优化Python数据类型的性能? 在Python编程中,数据类型是非常重要的。它们可以帮助我们更好地组织和操作数据。然而,在处理大量数据时,Python的解释器可能会变得缓慢。在这种情况下,我们需要一些优化方法来加快Pytho...
    99+
    2023-07-18
    数据类型 git 框架
  • 如何使用Python文件响应框架实现高可靠性的文件传输?
    如何使用Python文件响应框架实现高可靠性的文件传输? 在今天的数字化时代,文件传输已成为必不可少的一部分。无论是传输视频、音频、图片还是文档,都需要一种可靠的方式来完成。而Python文件响应框架可以提供一种高可靠性的文件传输解决方案。...
    99+
    2023-07-20
    响应 文件 框架
  • LeetCode中如何使用Python实现Spring框架的负载均衡?
    在现代的互联网应用中,负载均衡已经成为了一个非常重要的组件。负载均衡可以让我们的应用更加健壮、更加高效,同时也可以让我们更加容易地扩展我们的应用。Spring框架是一个非常流行的Java框架,它提供了很多强大的功能,其中就包括负载均衡。在...
    99+
    2023-06-17
    leetcode load spring
  • 如何使用Golang实现网关(框架分享)
    随着互联网的快速发展,越来越多的应用需要进行后端接口的开发,而这些接口的调用涉及了多个服务的协同,因此需要一个统一的入口进行管理和控制。这个入口就是网关。Golang作为一门高效的编程语言,近年来在网关的实现中有着愈发广泛的应用。下面将介绍...
    99+
    2023-05-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作