中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python ORM框架如何實現

發布時間:2022-02-23 09:48:02 來源:億速云 閱讀:233 作者:iii 欄目:開發技術

這篇文章主要介紹了Python ORM框架如何實現的相關知識,內容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Python ORM框架如何實現文章都會有所收獲,下面我們一起來看看吧。

    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)

    關于“Python ORM框架如何實現”這篇文章的內容就介紹到這里,感謝各位的閱讀!相信大家對“Python ORM框架如何實現”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    淮北市| 新民市| 东乡族自治县| 莱州市| 汪清县| 乡宁县| 五河县| 金秀| 柳林县| 榕江县| 山东省| 耿马| 延津县| 大姚县| 新营市| 广安市| 塔城市| 涿鹿县| 汝南县| 得荣县| 晴隆县| 陇南市| 甘德县| 措勤县| 陵水| 施秉县| 南安市| 福建省| 二连浩特市| 潜江市| 鹤岗市| 左权县| 亚东县| 原阳县| 高雄县| 赫章县| 榆社县| 雷波县| 游戏| 万载县| 江孜县|