一、前言
看别人源码写的简易ORM
二、代码
"""
定义一个模型的基类和元类
"""
import asyncio
from datetime import datetime
from typing import Dict
from 工具.motorORM.校验异常 import FieldValidationError
from 工具.motorORM.校验类 import Field, StringField
from 数据库.操作 import motor_obj
class ModelMeta(type):
"""
模型的元类
在创建类的时候,将变量名传递到验证类的实例里,并进行校验
"""
def __new__(mcs, name, bases, attrs):
# 如果是model基类,就直接创建
if name == "Model":
return type.__new__(mcs, name, bases, attrs)
# 判断abstract,决定是否过滤
metainfo = attrs.get('Meta', None)
if getattr(metainfo, "abstract", None):
return type.__new__(mcs, name, bases, attrs)
newobj = type.__new__(mcs, name, bases, attrs)
# 剩下的都是标准子类,进行过滤
items = {}
fields = {}
for k, v in attrs.items():
if isinstance(v, Field):
v.__set__("name", k)
items[k] = 1
fields[k] = v
setattr(newobj, "fields", fields)
# 设置默认表名
if not getattr(metainfo, "tablename", None):
setattr(metainfo, "tablename", [])
# 设置默认排序
if not getattr(metainfo, "ordering", None):
setattr(metainfo, "ordering", [])
setattr(newobj, "items", items)
setattr(newobj, "_meta", metainfo)
setattr(newobj, "motor_obj", motor_obj)
return newobj
class Model(metaclass=ModelMeta):
"""
模型的基类
"""
motor_obj = motor_obj
def __init__(self, **kwargs):
# 初始化的时候,从fields取出类的字段,给实例
for k, v in self.fields.items():
self[k] = v
# 初始化时,从meta获取数据库链接
self.db = self.motor_obj.db[self._meta.tablename]
# 初始化时,如果传递进来数值,将赋值到self.items上
self.set_items_value(**kwargs)
# 定义空字段进行群查过滤条件
self.filteritem = {}
# 定义排序字段
self.order = []
def __getitem__(self, item):
return self.__dict__[item]
def __setitem__(self, key, value):
self.__dict__[key] = value
def __set__(self, instance, value):
self[instance].value = value
def set_items_value(self, **kwargs):
# 过滤出模型含有的字段,赋值给验证实例,触发验证。
for k in self.items.keys():
if kwargs.get(k, None):
self[k].__set__("value", kwargs[k])
# 将数据整理成字典,方便插入
def get_dict(self):
jieguo = {}
for i in self.items.keys():
jieguo.update(self[i].getmodelfield())
return jieguo
async def create(self, **kwargs):
# 创建方法,先把值都传递进校验类实例里面进行校验
self.set_items_value(**kwargs)
# 检查唯一性
await self.check_unique()
# 如果没问题,就开始插入
jieguo1 = await self.db.insert_one(**self.get_dict())
return jieguo1
async def check_unique(self):
# 过滤出唯一字段,进行唯一性验证
for i in self.items.keys():
if self[i].unique:
await self.get_one(self[i].getmodelfield())
# 遍历联合唯一列表,进行唯一性验证
for i in self._meta.unique_together:
zidian = {}
for t in i:
zidian.update({t: self[t]})
await self.get_one(zidian)
# 排查唯一字段和联合唯一字段
async def get_one(self, item=None):
if item:
jieguo = await self.db.find_one(item)
if jieguo:
keylist = item.keys()
raise FieldValidationError({",".join(keylist): f"不是唯一的"})
# 查询一个数据
async def first(self, getitem=None):
if not getitem:
jieguo = await self.db.find_one(self.filteritem, self.items)
else:
jieguo = await self.db.find_one(self.filteritem, getitem)
return jieguo
# 查询多个数据
async def all(self, fenye=None, getitem=None):
jieguo = []
# 先获取数据
if getitem:
shuju = self.db.find(self.filteritem, getitem)
else:
shuju = self.db.find(self.filteritem, self.items)
# 然后排序
if isinstance(self.order, str):
shuju = shuju.sort(self.order)
elif isinstance(self.order, list) or isinstance(self.order, tuple):
shuju = shuju.sort(",".join(self.order))
# 最后分页
if fenye:
shuju = shuju.skip((fenye["p"] - 1) * fenye["psize"]).limit(fenye["psize"])
for i in await shuju.to_list(length=100):
jieguo.append(i)
return jieguo
# 更新数据,不能修改editable为true的
async def update(self, obj: Dict, **kwargs):
"""
replace_one()是全部修改,不需要“$set”
update_one()是部分修改,需要添加”$set“
"""
# 过滤出要更新的字段,注意过滤不能修改的字段
keylist = self.items.keys()
updateitem = {}
for k, v in kwargs.items():
if k in keylist and not self[k].editdisable:
updateitem[k] = v
if updateitem != {}:
# 过滤完数据后,放到验证类实例里面进行验证
self.set_items_value(**updateitem)
# 验证完后,再取出来
shuju = {}
for i in updateitem.keys():
shuju.update(self[i].getmodelfield())
# 更新的时候,需要修改changetime
shuju["changeTime"] = datetime.now()
jieguo = await self.db.update_one(obj, shuju)
return jieguo
return obj
async def delete(self, itemid: str):
# 使用逻辑删除方式删除数据
obj = await self.db.find_one({"id": itemid})
if not obj:
raise FieldValidationError({itemid: f"id:{itemid}对应的数据不存在"})
jieguo = await self.db.update_one(obj, {"$set": {"deleteTime": datetime.now(), "isDelete": True}})
return jieguo
async def filter(self, item):
self.filteritem.update(item)
def __str__(self):
return self._meta.tablename
# 测试用方法,一会删除
async def getall(self):
thisjieguo = []
for i in await self.db.find().to_list(100):
thisjieguo.append(i)
return thisjieguo
class Meta:
abstract = False # 基类
unique_together = () # 联合唯一
ordering = "" # 默认排序
tablename = "" # 表名,必填
class Ceshi(Model):
"""
测试类
"""
pk = StringField(max_length=50, help_text="主键ID")
class Meta:
tablename = "worker"
if __name__ == '__main__':
ceshi = Ceshi(id=6565)
# loop = asyncio.get_event_loop()
# jieguo = loop.run_until_complete(ceshi.getall())
print("打印结果")
print(ceshi.id, type(ceshi.id))