初识orm

初识orm

一、什么是orm

  • 介绍
ORM: 对象关系映射
    将随对象映射成 数据表中的鱼跳跳记录

    类--->表名
    对象--->记录
    对象.属性--->字段
    
# 演示映射关系
'''
User table:名字、年龄、性别
    
    class User
    user_obj = User()
    user_obj.name属性
    user_obj.age 属性

'''
  • 演示orm以及自定义元类
# 定义字段类型:每个字段都应该有---> 字段名、字段类型、是否为主键、默认值
# 字段父类
#
# class Field:
#     def __init__(self, name, column_type, primary_key, default):
#         self.name = name
#         self.column_type = column_type
#         self.primary_key = primary_key
#         self.default = default
#
#
# # varchar
# class StringField(Field):
#     def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None):
#
#         super().__init__(name, column_type, primary_key, default)
#
#
#
#
# # int
# class IntegerField(Field):
#     def __init__(self, name, column_type='int', primary_key=False, default=0):
#         super().__init__(name, column_type, primary_key, default)
#
#
# #自定义元类
# '''
# 解决了三件事:
# 1、保证一张表必须要有表名
# 2、保证一张表中只能有一个主键
# 3、将所有“字段名” 与 “字段对象” 添加到一个独立的字典中(mappings)
# 以 key(字段名):values(字段对象),添加到类的名称空间中,方便后期使用
# '''
#
# class OrmMetaClass(type):
#
#     # def __new__(cls, *args, **kwargs):
#     #     class_name, class_bases, class_attr = args
#     #     print(f'类名:{class_name}')
#     #     print(f'基类:{class_bases}')
#     #     print(f'类的名称空间:{class_attr}')
#     def __new__(cls, class_name, class_bases, class_attr):
#
#         # 1、过滤Models类
#
#
#
#
#
#
#
#
# class Models(dict, metaclass=OrmMetaClass):
#
#     # 对象.属性  没有时触发
#     def __getattr__(self, item):
#
#         return self.get(item)    # # {'name': 'tank', 'pwd': '123'}.get('name')
#
#     # 对象.属性 = 属性值  时触发
#     def __setattr__(self, key, value):
#
#         # 给字典添加键值对的方式
#         self[key] = value
#
#
#
#
# # User  用户名 密码
# class User(Models):
#
#     # 用户自定义,表名为 user_info
#     # table_name = 'user_info'
#     #
#     # obj = IntegerField(name='id', primary_key=True)
#     # print(obj.primary_key)
#     # print(obj.name)
#     # print(obj.default)
#
#     # IntegerField字段类中的name属性 必须与User表中类属性同名
#     id = IntegerField(name='id', primary_key=True)
#     username = StringField(name='username')
#     password = StringField(name='password')


#
# if __name__ == '__main__':
#     user_dic = dict({'name': 'tank', 'pwd': '123'})
#
#     print(type(user_dic))
#
#
#     user_obj = User(naem='tank', pwd='123')
#     # print(user_obj)
#     # print(user_obj.__dict__)
#     # 问题1 通过对象.属性 的方式无法获取属性值 只能通过字典的取值方式获取 因为继承的是dict字典类
#     # print(user_obj.name)
#     # print(user_obj.get('name'))
#     # print(user_obj['name'])
#     # print(type(user_obj))
#
#     # 问题2:继续的字典无法通过  对象.属性的 取值方式  , 对象.属性 = 属性值 增加或修改属性的操作
#     # 解决2: __getattr__解决了取值方式,__setattr__解决了增加或修改属性的方式
#     # print(user_obj.name)
#
#     print(user_obj.__dict__)
#     print('添加属性前:--->', user_obj)
#
#
#     # User 类实例化出来的 user_obj 普通对象 添加属性的方式
#     user_obj.user_type = 'admin'
#     print(user_obj.__dict__)
#
#     print('添加属性后:--->', user_obj)







class Field:
    def __init__(self, name, column_type, primary_key, default):
        self.name = name
        self.column_type = column_type
        self.primary_key = primary_key
        self.default = default


# varchar
class StringField(Field):
    def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None):
        super().__init__(name, column_type, primary_key, default)


# int
class IntegerField(Field):
    def __init__(self, name, column_type='int', primary_key=False, default=0):
        super().__init__(name, column_type, primary_key, default)


# 自定义元类
'''
解决了三件事:
1、保证一张表必须要有表名
2、保证一张表中只能有一个主键
3、将所有“字段名” 与 “字段对象” 添加到一个独立的字典中(mappings)
以 key(字段名):values(字段对象),添加到类的名称空间中,方便后期使用
'''

from mysql_control import MySQL

class OrmMetaClass(type):

    # def __new__(cls, *args, **kwargs):
    #     class_name, class_bases, class_attr = args
    #     print(f'类名:{class_name}')
    #     print(f'基类:{class_bases}')
    #     print(f'类的名称空间:{class_attr}')
    def __new__(cls, class_name, class_bases, class_attr):



        # 1、过滤Models类
        if class_name == 'Models':
            # 将models类的类名,基类,名称空间原路返回
            return type.__new__(cls,  class_name, class_bases, class_attr)

        # 2、获取 table 表名 ,若自定义则获取自定义的表名,没有则默认使用类名做表名
        # dict.get(key) ---> key若有则返回对应的值,若没有则返回默认追 class_name 就是默认值
        table_name = class_attr.get('table_name', class_name)
        # print(table_name)

        # 主键值:主键名为:字段名,比如主键是 id字段 ---> id就是主键的名字
        primary_key = None

        # 存放字段名与字段对象的字典
        mappings = {}

        # 3、保证一张表只能有唯一的一个主键
        # 循环遍历类的名字
        for k, v in class_attr.items():
            # print(k, v)
            # 将字段以外的属性过滤掉
            # 判断当前的v是否是字段对象
            if isinstance(v, Field):
                # print(k, v)
                # print(v.__dict__)
                # 4、将所有 “字段名”  与 “字段对象” 添加到一个独立的字典中(mappings)
                mappings[k] = v


                # 坑
                # class_attr.pop(k) # 纠正 ,这里当字典被迭代时,不能直接修改其属性

                # 判断字段对象 如果有 主键primary_key, 则为primary_key 变量赋值
                if v.primary_key:
                    # 若第二次进来,primary_key 有值,证明有主键 ,抛出异常
                    if primary_key:
                        raise TypeError('一张表只能有一个主键')

                    # primary_key = k
                    # 给primary_key变量做一个赋值操作
                    primary_key = v.name


        # 5、过滤掉类名称空间中重复的字段属性
        for key in mappings.keys():
            class_attr.pop(key)


        # print(table_name)
        # print(mappings)
        # print(class_attr)

        if not primary_key:
            raise TypeError('必须要有一个主键!!!')

        # 6、给类的名称空间,添加table_name, primary_key, mappings属性
        class_attr['table_name'] = table_name
        class_attr['primary_key'] = primary_key
        class_attr['mappings'] = mappings

        # print('*' * 100)
        # print(class_attr)

        return type.__new__(cls, class_name, class_bases, class_attr)





class Models(dict, metaclass=OrmMetaClass):

    # 对象.属性  没有时触发
    def __getattr__(self, item):
        return self.get(item)  # # {'name': 'tank', 'pwd': '123'}.get('name')

    # 对象.属性 = 属性值  时触发
    def __setattr__(self, key, value):
        # 给字典添加键值对的方式
        self[key] = value


# User  用户名 密码
class User(Models):
    # 用户自定义,表名为 user_info
    # table_name = 'user_info'
    #
    # obj = IntegerField(name='id', primary_key=True)
    # print(obj.primary_key)
    # print(obj.name)
    # print(obj.default)

    # IntegerField字段类中的name属性 必须与User表中类属性同名
    id = IntegerField(name='id', primary_key=True)
    username = StringField(name='username')
    password = StringField(name='password')

  • mysql_cntrol
import pymysql

# MySQL连接类

class MySQL:

    __instance = None

    # 单例模式
    @classmethod
    def singleton(cls):
        if not cls.__instance:
            cls.__instance = cls()

        return cls.__instance


    # 实例化MySQL类时,获取数据库连接对象,获取游标对象
    def __init__(self):
        self.mysql_client = pymysql.connect(
            host = '127.0.0.1',
            port = 3306,
            user = 'root',
            password = '123456',
            charset = 'utf8',
            database = 'orm_demo',
            autocommit = True
        )

        self.cursor = self.mysql_client.cursor(pymysql.cursors.DictCursor)

    # 自定义查询方法
    def select(self, sql, args= None):
        # 1、先提交查询sql语句
        # select * from tabele;
        # select * from table where id=%s;
        self.cursor.execute(sql, args)

        # 2、获取返回的查询结果
        # res ---> [{}, {}]
        res = self.cursor.fetchall()
        return res


    # 自定义提交sql语句方法, 比如inset ,update
    def execute(self, sql, args):

        # 1、提交sql语句
        # insert into table(字段) values(%s);
        try:
            self.cursor.execute(sql, args)

        except Exception as e:
            print(e)


    def close(self):

        # 先关闭游标
        self.cursor.close()
        # 再关闭数据库连接
        self.mysql_client.close()


if __name__ == '__main__':

    mysal_obj1 = MySQL.singleton()
    mysal_obj2 = MySQL.singleton()
    print(id(mysal_obj1))
    print(id(mysal_obj2))



posted @ 2019-12-18 21:51  alen_zhan  阅读(153)  评论(0编辑  收藏  举报
返回顶部