最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

用 Python 元類的特性實(shí)現(xiàn) ORM 框架

 更新時(shí)間:2021年05月19日 17:07:51   作者:憶想不到的暉  
利用 Python 元類的特性實(shí)現(xiàn) ORM 框架的 insert 功能,通過(guò)操作類對(duì)象,對(duì)數(shù)據(jù)表進(jìn)行數(shù)據(jù)增加操作。由于 ORM 比較復(fù)雜,也不要重復(fù)造輪子,就完成一個(gè) insert 相類似的ORM,理解其中的道理即可。

ORM是什么

O是 object,也就 類對(duì)象 的意思,R是 relation,翻譯成中文是 關(guān)系,也就是關(guān)系數(shù)據(jù)庫(kù)中 數(shù)據(jù)表 的意思,M是 mapping,是映射的意思。在ORM框架中,它幫我們把類和數(shù)據(jù)表進(jìn)行了一個(gè)映射,可以讓我們通過(guò)類和類對(duì)象就能操作它所對(duì)應(yīng)的表格中的數(shù)據(jù)。ORM框架還有一個(gè)功能,它可以根據(jù)我們?cè)O(shè)計(jì)的類自動(dòng)幫我們生成數(shù)據(jù)庫(kù)中的表,省去了我們自己建表的過(guò)程。

一個(gè)句話理解就是:創(chuàng)建一個(gè)實(shí)例對(duì)象,用創(chuàng)建它的類名當(dāng)做數(shù)據(jù)表名,用創(chuàng)建它的類屬性對(duì)應(yīng)數(shù)據(jù)表的字段,當(dāng)對(duì)這個(gè)實(shí)例對(duì)象操作時(shí),能夠?qū)?yīng) MySQL 語(yǔ)句。

在 Django 中就內(nèi)嵌了一個(gè) ORM 框架,不需要直接面向數(shù)據(jù)庫(kù)編程,而是定義模型類,通過(guò)模型類和對(duì)象完成數(shù)據(jù)表的增刪改查操作。還有第三方庫(kù) sqlalchemy 都是 ORM框架。

先看看我們大致要實(shí)現(xiàn)什么功能

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

# 對(duì)應(yīng)如下sql語(yǔ)句
# insert into User (uid,username,email,password) values (123,hui,huidbk@163.com,123456)

所謂的 ORM 就是讓開(kāi)發(fā)者在操作數(shù)據(jù)庫(kù)的時(shí)候,能夠像操作對(duì)象時(shí)通過(guò)xxxx.屬性=yyyy一樣簡(jiǎn)單,這是開(kāi)發(fā)ORM的初衷。

實(shí)現(xiàn)ORM中的insert功能

通過(guò) Python 中 元類 簡(jiǎn)單實(shí)現(xiàn) ORM 中的 insert 功能

# !/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Hui
# @Desc: { 利用Python元類簡(jiǎn)單實(shí)現(xiàn)ORM框架的Insert插入功能 }
# @Date: 2021/05/17 17:02


class ModelMetaclass(type):
    """數(shù)據(jù)表模型元類"""

    def __new__(mcs, cls_name, bases, attrs):

        print(f'cls_name -> {cls_name}')    # 類名
        print(f'bases -> {bases}')          # 繼承類
        print(f'attrs -> {attrs}')          # 類中所有屬性
        print()

        # 數(shù)據(jù)表對(duì)應(yīng)關(guān)系字典
        mappings = dict()

        # 過(guò)濾出對(duì)應(yīng)數(shù)據(jù)表的字段屬性
        for k, v in attrs.items():
            # 判斷是否是指定的StringField或者IntegerField的實(shí)例對(duì)象
            # 這里就簡(jiǎn)單判斷字段是元組
            if isinstance(v, tuple):
                print('Found mapping: %s ==> %s' % (k, v))
                mappings[k] = v

        # 刪除這些已經(jīng)在字典中存儲(chǔ)的字段屬性
        for k in mappings.keys():
            attrs.pop(k)

        # 將之前的uid/name/email/password以及對(duì)應(yīng)的對(duì)象引用、類名字
        # 用其他類屬性名稱保存
        attrs['__mappings__'] = mappings  # 保存屬性和列的映射關(guān)系
        attrs['__table__'] = cls_name     # 假設(shè)表名和類名一致
        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__
        # 數(shù)據(jù)表中的字段
        fields = ','.join(fields)
        # 待插入的數(shù)據(jù)
        args = ','.join([str(i) for i in args])
        
        # 生成sql語(yǔ)句
        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()

當(dāng) User 指定元類之后,uid、name、email、password 類屬性將不在類中,而是在 __mappings__ 屬性指定的字典中存儲(chǔ)。 User 類的這些屬性將轉(zhuǎn)變?yōu)槿缦?/p>

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

執(zhí)行的效果如下:

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)

完善對(duì)數(shù)據(jù)類型的檢測(cè)

上面轉(zhuǎn)成的 sql 語(yǔ)句如下:

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

發(fā)現(xiàn)沒(méi)有,在 sql 語(yǔ)句中字符串類型沒(méi)有沒(méi)有引號(hào) ''

正確的 sql 語(yǔ)句應(yīng)該是:

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

因此修改 User 類完善數(shù)據(jù)類型的檢測(cè)

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)

    # 在這里完善數(shù)據(jù)類型檢測(cè)
    def save(self):
        fields = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v[0])
            args.append(getattr(self, k, None))

        # 把參數(shù)數(shù)據(jù)類型對(duì)應(yīng)數(shù)據(jù)表的字段類型
        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__
        # 數(shù)據(jù)表中的字段
        fields = ','.join(fields)
        # 待插入的數(shù)據(jù)
        args = ','.join(args_temp)

        # 生成sql語(yǔ)句
        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()

運(yùn)行效果如下:

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元類實(shí)現(xiàn)ORM框架的Insert插入功能 }
# @Date: 2021/05/17 17:02


class ModelMetaclass(type):
    """數(shù)據(jù)表模型元類"""

    def __new__(mcs, cls_name, bases, attrs):

        print(f'cls_name -> {cls_name}')  # 類名
        print(f'bases -> {bases}')  # 繼承類
        print(f'attrs -> {attrs}')  # 類中所有屬性
        print()

        # 數(shù)據(jù)表對(duì)應(yīng)關(guān)系字典
        mappings = dict()

        # 過(guò)濾出對(duì)應(yīng)數(shù)據(jù)表的字段屬性
        for k, v in attrs.items():
            # 判斷是否是對(duì)應(yīng)數(shù)據(jù)表的字段屬性, 因?yàn)閍ttrs中包含所有的類屬性
            # 這里就簡(jiǎn)單判斷字段是元組
            if isinstance(v, tuple):
                print('Found mapping: %s ==> %s' % (k, v))
                mappings[k] = v

        # 刪除這些已經(jīng)在字典中存儲(chǔ)的字段屬性
        for k in mappings.keys():
            attrs.pop(k)

        # 將之前的uid/name/email/password以及對(duì)應(yīng)的對(duì)象引用、類名字
        # 用其他類屬性名稱保存
        attrs['__mappings__'] = mappings  # 保存屬性和列的映射關(guān)系
        attrs['__table__'] = cls_name  # 假設(shè)表名和類名一致
        return type.__new__(mcs, cls_name, bases, attrs)


class Model(object, metaclass=ModelMetaclass):
    """數(shù)據(jù)表模型基類"""

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

        # 把參數(shù)數(shù)據(jù)類型對(duì)應(yīng)數(shù)據(jù)表的字段類型
        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__
        # 數(shù)據(jù)表中的字段
        fields = ','.join(fields)
        # 待插入的數(shù)據(jù)
        args = ','.join(args_temp)

        # 生成sql語(yǔ)句
        sql = f"""insert into {table_name} ({fields}) values ({args})"""
        print(f'SQL: {sql}')

        # 執(zhí)行sql語(yǔ)句
        # ...


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

添加數(shù)據(jù)庫(kù)驅(qū)動(dòng)執(zhí)行sql語(yǔ)句

這里我們使用 pymysql 數(shù)據(jù)庫(kù)驅(qū)動(dòng),來(lái)執(zhí)行 sql 語(yǔ)句

在 Model 類中新增一個(gè) get_connection 的靜態(tài)方法用于獲取數(shù)據(jù)庫(kù)連接

import pymysql


class Model(object, metaclass=ModelMetaclass):
    """數(shù)據(jù)表模型基類"""

    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    @staticmethod
    def get_connection():
        """
        獲取數(shù)據(jù)庫(kù)連接與數(shù)據(jù)游標(biāo)
        :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))

        # 把參數(shù)數(shù)據(jù)類型對(duì)應(yīng)數(shù)據(jù)表的字段類型
        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__
        # 數(shù)據(jù)表中的字段
        fields = ','.join(fields)
        # 待插入的數(shù)據(jù)
        args = ','.join(args_temp)

        # 生成sql語(yǔ)句
        sql = f"""insert into {table_name} ({fields}) values ({args})"""
        print(f'SQL: {sql}')

        # 執(zhí)行sql語(yǔ)句
        conn, cursor = self.get_connection()
        ret = cursor.execute(sql)
        print(ret)
        conn.commit()
        cursor.close()
        conn.close()
        

添加數(shù)據(jù)庫(kù)驅(qū)動(dòng)執(zhí)行sql語(yǔ)句

這里我們使用 pymysql 數(shù)據(jù)庫(kù)驅(qū)動(dòng),來(lái)執(zhí)行 sql 語(yǔ)句

在 Model 類中新增一個(gè) get_connection 的靜態(tài)方法用于獲取數(shù)據(jù)庫(kù)連接

import pymysql


class Model(object, metaclass=ModelMetaclass):
    """數(shù)據(jù)表模型基類"""

    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    @staticmethod
    def get_connection():
        """
        獲取數(shù)據(jù)庫(kù)連接與數(shù)據(jù)游標(biāo)
        :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))

        # 把參數(shù)數(shù)據(jù)類型對(duì)應(yīng)數(shù)據(jù)表的字段類型
        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__
        # 數(shù)據(jù)表中的字段
        fields = ','.join(fields)
        # 待插入的數(shù)據(jù)
        args = ','.join(args_temp)

        # 生成sql語(yǔ)句
        sql = f"""insert into {table_name} ({fields}) values ({args})"""
        print(f'SQL: {sql}')

        # 執(zhí)行sql語(yǔ)句
        conn, cursor = self.get_connection()
        ret = cursor.execute(sql)
        print(ret)
        conn.commit()
        cursor.close()
        conn.close()
        

測(cè)試功能

準(zhǔn)備數(shù)據(jù)庫(kù)

先準(zhǔn)備數(shù)據(jù)庫(kù) testdb 和 user 數(shù)據(jù)表

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 表結(jié)構(gòu)如下

+----------+------------------+------+-----+---------+----------------+
| 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    |                |
+----------+------------------+------+-----+---------+----------------+

創(chuàng)建模型類測(cè)試

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

查看數(shù)據(jù)庫(kù) user 表數(shù)據(jù)

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知識(shí)寶庫(kù),歡迎大家來(lái)訪。

以上就是用 Python 元類的特性實(shí)現(xiàn) ORM 框架的詳細(xì)內(nèi)容,更多關(guān)于Python 實(shí)現(xiàn) ORM 框架的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python解決雞兔同籠問(wèn)題的方法

    Python解決雞兔同籠問(wèn)題的方法

    這篇文章主要介紹了Python解決雞兔同籠問(wèn)題的方法,分析了雞兔同籠問(wèn)題的原理與解決思路,并給出了Python實(shí)現(xiàn)的代碼,非常具有參考借鑒價(jià)值,需要的朋友可以參考下
    2014-12-12
  • Python?Tkinter庫(kù)從入門到進(jìn)階使用教程

    Python?Tkinter庫(kù)從入門到進(jìn)階使用教程

    Tkinter是Python標(biāo)準(zhǔn)庫(kù)中內(nèi)置的圖形用戶界面(GUI)工具包,提供了創(chuàng)建窗口、按鈕、文本框等GUI元素的功能,本文將介紹Tkinter的基礎(chǔ)知識(shí),幫助大家快速入門
    2023-12-12
  • 詳解Python的Flask框架中的signals信號(hào)機(jī)制

    詳解Python的Flask框架中的signals信號(hào)機(jī)制

    這里將為大家來(lái)詳解Python的Flask框架中的signals信號(hào)機(jī)制,包括講述信號(hào)的用途,并給出創(chuàng)建信號(hào)、訂閱信號(hào)、發(fā)送信號(hào)的方法,需要的朋友可以參考下
    2016-06-06
  • python中while和for的區(qū)別總結(jié)

    python中while和for的區(qū)別總結(jié)

    在本篇內(nèi)容里小編給大家分享的是關(guān)于python中while和for的區(qū)別以及相關(guān)知識(shí)點(diǎn),需要的朋友們可以學(xué)習(xí)下。
    2019-06-06
  • OpenCV實(shí)現(xiàn)圖片編解碼實(shí)踐

    OpenCV實(shí)現(xiàn)圖片編解碼實(shí)踐

    在很多應(yīng)用中,經(jīng)常會(huì)直接把圖片的二進(jìn)制數(shù)據(jù)進(jìn)行交換,這就需要對(duì)普通進(jìn)行編碼解碼,那么怎么才能實(shí)現(xiàn),本文就來(lái)介紹一下
    2021-06-06
  • 三行Python代碼提高數(shù)據(jù)處理腳本速度

    三行Python代碼提高數(shù)據(jù)處理腳本速度

    Python是一門非常適合處理數(shù)據(jù)和自動(dòng)化完成重復(fù)性工作的編程語(yǔ)言,我們?cè)谟脭?shù)據(jù)訓(xùn)練機(jī)器學(xué)習(xí)模型之前,通常都需要對(duì)數(shù)據(jù)進(jìn)行預(yù)處理,而Python就非常適合完成這項(xiàng)工作。本文將為大家介紹如何利用Python代碼讓你的數(shù)據(jù)處理腳本快別人4倍,需要的可以參考一下
    2022-03-03
  • python3.6之xlwt如何設(shè)置單元格對(duì)齊方式

    python3.6之xlwt如何設(shè)置單元格對(duì)齊方式

    這篇文章主要介紹了python3.6之xlwt如何設(shè)置單元格對(duì)齊方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • python中tkinter窗口位置\坐標(biāo)\大小等實(shí)現(xiàn)示例

    python中tkinter窗口位置\坐標(biāo)\大小等實(shí)現(xiàn)示例

    這篇文章主要介紹了python中tkinter窗口位置\坐標(biāo)\大小等實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • python jieba庫(kù)的基本使用

    python jieba庫(kù)的基本使用

    這篇文章主要介紹了python jieba庫(kù)的基本使用,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下
    2021-03-03
  • python實(shí)現(xiàn)密碼強(qiáng)度校驗(yàn)

    python實(shí)現(xiàn)密碼強(qiáng)度校驗(yàn)

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)密碼強(qiáng)度校驗(yàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-03-03

最新評(píng)論

开鲁县| 罗定市| 重庆市| 乐至县| 岳普湖县| 富平县| 宁强县| 长寿区| 汾阳市| 瓮安县| 略阳县| 鹤庆县| 盘锦市| 偏关县| 论坛| 冀州市| 大荔县| 广南县| 抚宁县| 鄂托克前旗| 绍兴市| 青岛市| 松潘县| 苏州市| 长乐市| 平舆县| 三河市| 松桃| 兴国县| 北京市| 鞍山市| 建德市| 秦皇岛市| 丹寨县| 杂多县| 德惠市| 武义县| 濮阳县| 四会市| 武汉市| 奉新县|