1. ORM的架构:

核心函数:new, all, find_all, find_by,find.get,update,remove
各个支持子函数及其功能:
核心函数的实现流程:

2. 代码实践

import time
from utils import log # 自定义的工具函数包
from pymongo import MongoClient
mongua = MongoClient() #默认是MongoClient("mongodb://localhost:27017")
# mongua是一个mongo的客户端实例,用它来操作数据库,数据库操作表,表操作记录def timestamp():return int(time.time())def next_id(name):query = {'name': name,}update = {'$inc': {'seq': 1}}kwargs = {'query': query,'update': update,'upsert': True, # 如果不存在某字段就创建'new': True,    # new为true:返回个性后的文档,false:返回个性前的,默认是false}# 存储数据的 iddoc = mongua.db['data_id'] #等价于创建了db这个数据库,以及data_id这个表# find_and_modify 是一个原子操作函数new_id = doc.find_and_modify(**kwargs).get('seq')return new_idclass Mongua(object):__fields__ = ['_id',# (字段名, 类型, 值)('id', int, -1),('type', str, ''),('deleted', bool, False),('created_time', int, 0),('updated_time', int, 0),]@classmethoddef has(cls, **kwargs):"""检查一个元素是否在数据库中 用法如下User.has(id=1):param kwargs::return:"""return cls.find_one(**kwargs) is not Nonedef mongos(self, name):return mongua.db[name]._find()def __repr__(self):class_name = self.__class__.__name__properties = ('{0} = {1}'.format(k, v) for k, v in self.__dict__.items())return '<{0}: \n  {1}\n>'.format(class_name, '\n  '.join(properties))@classmethoddef new(cls, form=None, **kwargs):"""new 是给外部使用的函数"""name = cls.__name__# 创建一个空对象m = cls()# 把定义的数据写入空对象, 未定义的数据输出错误fields = cls.__fields__.copy()# 去掉 _id 这个特殊的字段fields.remove('_id')if form is None:form = {}for f in fields:k, t, v = f # 取出fieldsif k in form:setattr(m, k, t(form[k])) # 用 form来覆盖默认值else:# 设置默认值setattr(m, k, v)# 处理额外的参数 kwargsfor k, v in kwargs.items():if hasattr(m, k): # 再次覆盖默认值setattr(m, k, v)else:raise KeyError # 传入非法的k-v# 写入默认数据m.id = next_id(name)# print('debug new id ', m.id)ts = int(time.time())m.created_time = tsm.updated_time = ts# m.deleted = Falsem.type = name.lower()# 特殊 model 的自定义设置# m._setup(form)m.save()return m@classmethoddef _new_with_bson(cls, bson):"""这是给内部 all 这种函数使用的函数从 mongo 数据中恢复一个 model"""m = cls()fields = cls.__fields__.copy()# 去掉 _id 这个特殊的字段fields.remove('_id')for f in fields:k, t, v = f# log("k:{}, t:{}, v:{}".format(k,t,v))if k in bson:setattr(m, k, bson[k])else:# 设置默认值setattr(m, k, v)setattr(m, '_id', bson['_id'])# 这一句必不可少,否则 bson 生成一个新的_id# FIXME, 因为现在的数据库里面未必有 type# 所以在这里强行加上# 以后洗掉db的数据后应该删掉这一句m.type = cls.__name__.lower()return m@classmethoddef all(cls):# 按照 id 升序排序# name = cls.__name__# ds = mongua.db[name].find()# l = [cls._new_with_bson(d) for d in ds]# return lreturn cls._find()# TODO, 还应该有一个函数 find(name, **kwargs)@classmethoddef _find(cls, **kwargs):"""mongo 数据查询"""name = cls.__name__# TODO 过滤掉被删除的元素# kwargs['deleted'] = Falseflag_sort = '__sort'sort = kwargs.pop(flag_sort, None)ds = mongua.db[name].find(kwargs)if sort is not None:ds = ds.sort(sort)# log("ds, ", type(ds))# log("ds_list, ", [d for d in ds])l = [cls._new_with_bson(d) for d in ds]# log("l, ", l)return l@classmethoddef _find_raw(cls, **kwargs):name = cls.__name__ds = mongua.db[name]._find(kwargs)l = [d for d in ds]return l# 直接 list() 就好了# return list(l)@classmethoddef _clean_field(cls, source, target):"""清洗数据用的函数例如 User._clean_field('is_hidden', 'deleted')把 is_hidden 字段全部复制为 deleted 字段"""ms = cls._find()for m in ms:v = getattr(m, source)setattr(m, target, v)m.save()@classmethoddef find_by(cls, **kwargs):return cls.find_one(**kwargs)@classmethoddef find_all(cls, **kwargs):return cls._find(**kwargs)@classmethoddef find(cls, id):return cls.find_one(id=id)@classmethoddef get(cls, id):return cls.find_one(id=id)@classmethoddef find_one(cls, **kwargs):""""""# TODO 过滤掉被删除的元素kwargs['deleted'] = Falsel = cls._find(**kwargs)# print('find one debug', kwargs, l)if len(l) > 0:return l[0]else:return None@classmethoddef upsert(cls, query_form, update_form, hard=False):ms = cls.find_one(**query_form)if ms is None:query_form.update(**update_form)ms = cls.new(query_form)else:ms.update(update_form, hard=hard)return msdef update(self, form, hard=False):for k, v in form.items():if hard or hasattr(self, k):setattr(self, k, v)# self.updated_time = int(time.time()) fixmeself.save()def save(self):name = self.__class__.__name__mongua.db[name].save(self.__dict__)def delete(self):name = self.__class__.__name__query = {'id': self.id,}values = {'deleted': True}mongua.db[name].update_one(query, values)# self.deleted = True# self.save()def blacklist(self):b = ['_id',]return bdef json(self):_dict = self.__dict__d = {k: v for k, v in _dict.items() if k not in self.blacklist()}# TODO, 增加一个 type 属性return ddef data_count(self, cls):"""神奇的函数, 查看用户发表的评论数u.data_count(Comment):return: int"""name = cls.__name__# TODO, 这里应该用 type 替代fk = '{}_id'.format(self.__class__.__name__.lower())query = {fk: self.id,}count = mongua.db[name]._find(query).count()return count

转载于:https://www.cnblogs.com/LS1314/p/8609432.html

Mongodb-自己写一个ORM相关推荐

  1. python实现gui+mysql图书管理系统_用Python Django框架写一个图书管理系统LMS

    今天我会带大家真正写一个Django项目,对于入门来说是有点难度的,因为逻辑比较复杂,但是真正的知识就是函数与面向对象,这也是培养用Django思维写项目的开始 Django文件配置 Django模版 ...

  2. Java之手写实现ORM框架

    借鉴Mybatis框架手写一个ORM框架.mybatis整体架构中的整体思路是,首先解析一下配置文件,一个是框架的全局配置文件,一个是mapper配置文件,定义格式如下 <configurati ...

  3. 【Part2】用JS写一个Blog (node + vue + mongoDB)

    [Part1]用JS写一个Blog (node + vue + mongoDB) 上一节前后端项目分别初始化完成,这一小节我就从后端项目开始写.实现mongoDB数据库的连接. 整理后端目录 下面是通 ...

  4. 【Part1】用JS写一个Blog(node + vue + mongoDB)

    学习JS也有一段时间了,准备试着写一个博客项目,前后端分离开发,后端用node只提供数据接口,前端用vue-cli脚手架搭建,路由也由前端控制,数据异步交互用vue的一个插件vue-resourse来 ...

  5. 手把手教你写一个java的orm(二)

    创建映射关系 ​ 想要实现一个orm的功能,我觉得就是要将class和数据库中的表创建映射关系.把class的名称和表的名称,class属性名称和表的字段名称,属性类型与表的字段类型一一对应起来.可以 ...

  6. 自己动手写一个Golang ORM框架

    作者:smallyang,腾讯 IEG 运营开发工程师 当我深入的学习和了解了 GORM,XORM 后,我还是觉得它们不够简洁和优雅,有些笨重,有很大的学习成本.本着学习和探索的目的,于是我自己实现了 ...

  7. 手把手教你写一个Java的orm框架(4)

    开始准备生成sql 在上一篇里,我们已经取到了我们在生成sql语句中所需要的信息,这一篇里我们开始根据class来生成我们需要的sql.在这之前我们先确认几件事情 sql里的参数我们使用占位符的形式. ...

  8. 写一个MP3播放器(vuejs+nodejs+mongodb)

    写一个MP3播放器(vue-cli+element ui+express+mongoose) 最近刚学完vuejs,为了增进理解就写了个MP3播放器(用到了vuex,vue-router,es6).可 ...

  9. 【原创】如何写一个框架:步骤(下)

    [原创]如何写一个框架:步骤(上) 说明:写本文的时候作者完全是把脑子里的东西写了出来,没有参考任何的资料,所以对于每一项内容可能都是不完整的,不能作为一个完整的参考.有一些方法学的东西每个人都有自己 ...

最新文章

  1. 如果你去小公司带技术团队,可能需要做的事情
  2. 聊聊Spring事务失效的12种场景,太坑人了
  3. linux temp文件夹在哪_Win10系统下使用linux命令的方法
  4. WebGIS概述:WebGIS基础(1)
  5. python百分号用法_python百分号%—%s、%d、%f
  6. leetcode1314. 矩阵区域和(动态规划)
  7. Bailian2798 2进制转化为16进制【进制】
  8. 学习微软企业库存心得--总结
  9. 实现一个进度条的打印
  10. 阿里P9技术:我来聊聊百万年薪
  11. python将图片转换成手绘_利用Python生成手绘效果的图片
  12. 信息安全与密码学概论
  13. 简单通用文章系统后台管理模板
  14. epicor数据表增加字段
  15. 【NOIP2015模拟10.28B组】终章-剑之魂题解
  16. GraphGallery,一个基于TensorFlow 2.x与 PyTorch 的GNN benchmark 框架
  17. 这些网络故障的处理手段,你都试过了吗
  18. 以下不属于C语言字符集的为,c语言第1章练习题答案
  19. FineReport中如何制作树数据集来实现组织树报表
  20. java文件恢复软件,文件恢复软件 免费-文件恢复软件 免费版

热门文章

  1. 性能优化——统计信息——SQLServer自动更新和自动创建统计信息选项
  2. Pictures for active reading.Unit 1 Food and health.
  3. javascript, jQuery阻止默认事件和冒泡事件
  4. XPath-Helper 的安装和使用
  5. XML学习笔记之XML的简介
  6. 算法笔记-图--bfs
  7. win8 app内存溢出检测工具PerfView.exe的使用
  8. POJ 1125 Stockbroker Grapevine
  9. monocross 环境搭建:MonoTouch Mono for Android
  10. c++模板之函数指针到函数对象: