一、ORM
之前我们都是以文件保存的形式存储数据,这次我们用的是数据库结合python使用,用到
ORM:关系型映射
类》》数据库的一张表
对象》》表一条记录
对象.属性》》记录某一个字段对应的值
关于ORM我们其实可以调用别人已经写好的,这次我们是自己写ORM。
这个就是在Django中调用别人的写好的
字段四要素:
- 字段名
- 字段类型
- 主键
- 默认值
1.先设计字段类型(这次只会用到两个字段类型,所以只设计两个)
#定义字段类型 name,column_type,primary_key,default (字段名,字段类型,主键,默认值) class Field(object): 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 #下面这些类型也可以不定义,但是你每次调用Field的时候,每个参数值都需要写 #定义varchar字段类型(针对于字段类型是varchar的) class StringField(Field): def __init__(self,name,column_type = 'varchar(32)',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)
2.设计模型表
继承字典类型,可以接收任意个数的关键字参数
所有模型表都继承Models,Models继承dict,__getattr__是当通过对象.属性的方式取值,属性不存在的话,就会触发这个方法
__setattr__是当新增或者修改属性的时候就会触发这个方法
class Models(dict,metaclass = Mymetaclass) def __init__(self,**kwargs): #接收任意多个关键字参数 super().__init__(**kwargs) #继承dict def __getattr__(self, item): #item是不存在的属性名 self是一个字典对象 return self.get(item) def __setattr__(self, key, value): #新增或者修改属性都会走这个 self[key] = value
表三要素:
- 表名
- 字段们
- 主键
3.使用元类,拦截自定义模型表的创建过程
使用元类,在类创建的时候把表名、字段、主键塞给类
类在创建的三个步骤:
1.__new__产生一个空对象
2.__init__实例化
3.将产生的对象返回
class MyMetaclass(type): #需要设置表名,主键,字段 def __new__(cls,class_name,class_bases,class_attr): #__new__创建一个空对象,class_name(类名),class_bases(基类们),class_attr(名称空间) #自定义元类是拦截模型表的创建过程,而models并不是一张模型表,所以不需要它的创建过程 if class_name == 'Models': return type.__new__(cls,class_name,class_bases,class_attr) #如果是models直接返回type table_name = class_attr.get('table_name',class_name) #获取名称空间内的表名,没有就返回类名 primary_key = None mappings = {} #方便后面取值 for k,v in class_attr.items(): #循环获取名称空间的所有键值对 k:id,name v:IntegerField(),StringField()是对象 if isinstance(v,Field): #拿出所有自定义的字段属性 #将所有自定义表的字段全部存入字典中 mappings[k] = v if v.primary_key: #判断字段是否存在主键 if primary_key: raise TypeError('一张表只能存在一个主键') primary_key = v.name #设置主键字段名 #循环取出mappings的key(也就是自定义的字段名),因为后面要把自定义的mappings放进class_attr里面,为了节省空间所以把原来的键值对删除 for k in mappings.keys(): class_attr.pop(k) #将名称空间内的重复k,v键值对删除 #校验自定义的的表是否指定了主键字段 if not primary_key: raise TypeError('一张表必须要有一个主键') class_attr['table_name'] = table_name class_attr['primary_key'] = primary_key class_attr['mappings'] = mappings return type.__new__(cls,class_name,class_bases,class_attr)
4.结合pymsql模块,封装查询和提交语句
import pymysql from orm.db_pool import POOL class Mysql: def __init__(self): self.conn =POOL.connection() self.cursor = self.conn.cursor(pymysql.cursors.DictCursor) #创建游标 def close_db(self): self.cursor.close() self.conn.close() #查询 def select(self,sql,args = None): self.cursor.execute(sql,args) res = self.cursor.fetchall() #查询所有 [{},{},{}....] return res #封装提交 def myexecute(self,sql,args): try: self.cursor.execute(sql,args) except Exception as e: print(e)
二、项目书写
项目是由服务端和客户端组成,基于socket通信
未完