仿优酷系统的orm
仿优酷系统项目orm
首先orm分别是
object relationship mopping
对象关系映射
是将对象映射成数据表中的一条条记录
类 对应 表明
对象 对应 记录
对象.属性 对应 字段
大体的思路:
首先是字段父类型 Field 属性包含 字段名name, 字段类型column_type , 是否是主键primary_key, 默认值 default
接着:
字符串字段类 StringField
整型字段类型 IntegerField
自定义元类:OrmMetaClass
1.要保证每一张都必须要有表名
2.保证一张表中只能有一个主键
3.将所有的“字段名”与“字段对象”添加到一个独立的字典中(mappings),
再添加到类的名称空间中去, 以key(字段名):value(字段对象)
基本的步骤:
1.首先过滤models类
2.获取table表名,如果传过来的名称空间中有自定义的表名,就用自定义的,否则默认将类名作为表名
3.保证每一张表只能有一个唯一的主键
- 先给一个空的主键
- 再创建一个空的mappings集合
- 遍历里面的class_attr,过滤。。
- 将所有的字段名与字段对象存进mappings集合中
4.要过滤掉类的名称空间中的重复的字段属性
5.给类的名称空间中,添加table_name, primary_key , mappings
定义父类Models
1.为了在定义每个表对应的类时,不用重复的写 __ init __ 方法,以及不需要确定每张表的字段个数,以及字段的名字,让父类继承dict类
2.用 __ getattr __ 与 __ setattr __,让对象.属性可以取值,对象.属性=属性可以增加或修改属性
示例代码
# 字段的父类
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
# 字符串字段
class StringField(Field):
def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None):
super().__init__(name, column_type, primary_key, default)
# 整型字段
class IntegerField(Field):
def __init__(self, name, column_type='int', primary_key=False, default=0):
super().__init__(name, column_type, primary_key, default)
# 自定义元类
class OrmMetaClass(type):
def __new__(cls, class_name, class_bases, class_attr):
# 首先过滤掉无用的Models
if class_name == 'Models':
return type.__new__(cls, class_name, class_bases, class_attr)
# 获取table的值,有自定义的用自定义的,没有的话默认用类名来当做表明
table_name = class_attr.get('table_name', class_name)
# 保证每一张表都有唯一的一个主键
primary_key = None
# 创建一个空的集合,用来存放字段名,字段对象
mappings = {}
for k, v in class_attr.items():
if isinstance(v, Field):
if v.primary_key:
if primary_key:
raise TypeError('一个表中只能有一个主键!')
primary_key = k
mappings[k] = v
# 过滤掉重复的字段属性
for i in mappings.keys():
class_attr.pop(i)
#确保表中有主键
if not primary_key:
raise TypeError('一个表中必须要有一个主键!')
# 给类的名称空间中加上表名, 主键和mapping集合
class_attr['table_name'] = table_name
class_attr['primary_key'] = primary_key
class_attr['mappings'] = mappings
# 表的父类
class Models(dict, metaclass=OrmMetaClass):
# 在对象.属性属性不存在时,触发
def __getattr__(self, item):
return self.get(item)
# 在对象.属性=属性值时,触发
def __setattr__(self, key, value):
self[key] = value
# 用户表对应的类
class User(Models):
id = IntegerField(name='id', primary_key=True)
name = StringField(name='name')
age = IntegerField(name='age')
if __name__ == '__main__':
pass
mysql类的代码演示
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(
user='root',
password='555',
host='127.0.0.1',
port=3306,
charset='utf8',
database='yk_demo',
autocommit=True
)
# 生成的游标对象
self.cursor = self.mysql_client.cursor(
pymysql.cursors.DictCursor
)
# 自定义的查询方法
def select(self, sql, args=None):
try:
self.cursor.execute(sql, args)
res1 = self.cursor.fetchall()
return res1
except Exception as e:
return e
# 自定义的提交sql语句的方法
def execute(self, sql, args=None):
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__':
# obj1 = MySql.singleton()
# obj2 = MySql.singleton()
# print(id(obj1))
# print(id(obj2))
obj = MySql.singleton()
# res = obj.select('select *from user')
# print(res)
sql = 'insert into user(name) values(%s)'
obj.execute(sql, 'egon')