Django中的核心思想ORM---元类实现ORM

1. ORM是什么

ORM 是 python编程语言后端web框架 Django的核心思想,“Object Relational Mapping”,即对象-关系映射,简称ORM。

一个句话理解就是:创建一个实例对象,用创建它的类名当做数据表名,用创建它的类属性对应数据表的字段,当对这个实例对象操作时,能够对应MySQL语句

demo:

class User(父类省略):uid = ('uid', "int unsigned")name = ('username', "varchar(30)")email = ('email', "varchar(30)")password = ('password', "varchar(30)")...省略...u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
u.save()
# 对应如下sql语句
# insert into User (username,email,password,uid)
# values ('Michael','test@orm.org','my-pwd',12345)

说明

  1. 所谓的ORM就是让开发者在操作数据库的时候,能够像操作对象时通过xxxx.属性=yyyy一样简单,这是开发ORM的初衷
  2. 只不过ORM的实现较为复杂,Django中已经实现了 很复杂的操作,本节知识 主要通过完成一个 insert相类似的ORM,理解其中的道理就就可以了

2. 通过元类简单实现ORM中的insert功能

class ModelMetaclass(type):def __new__(cls, name, bases, attrs):mappings = dict()# 判断是否需要保存for k, v in attrs.items():# 判断是否是指定的StringField或者IntegerField的实例对象if isinstance(v, tuple):print('Found mapping: %s ==> %s' % (k, v))mappings[k] = v# 删除这些已经在字典中存储的属性for k in mappings.keys():attrs.pop(k)# 将之前的uid/name/email/password以及对应的对象引用、类名字attrs['__mappings__'] = mappings  # 保存属性和列的映射关系attrs['__table__'] = name  # 假设表名和类名一致return type.__new__(cls, name, bases, attrs)class User(metaclass=ModelMetaclass):uid = ('uid', "int unsigned")name = ('username', "varchar(30)")email = ('email', "varchar(30)")password = ('password', "varchar(30)")# 当指定元类之后,以上的类属性将不在类中,而是在__mappings__属性指定的字典中存储# 以上User类中有 # __mappings__ = {#     "uid": ('uid', "int unsigned")#     "name": ('username', "varchar(30)")#     "email": ('email', "varchar(30)")#     "password": ('password', "varchar(30)")# }# __table__ = "User"def __init__(self, **kwargs):for name, value in kwargs.items():setattr(self, name, value)def save(self):fields = []args = []for k, v in self.__mappings__.items():fields.append(v[0])args.append(getattr(self, k, None))sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join([str(i) for i in args]))print('SQL: %s' % sql)u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()

执行的效果:

Found mapping: password ==> ('password', 'varchar(30)')
Found mapping: email ==> ('email', 'varchar(30)')
Found mapping: uid ==> ('uid', 'int unsigned')
Found mapping: name ==> ('username', 'varchar(30)')
SQL: insert into User (uid,password,username,email) values (12345,my-pwd,Michael,test@orm.org)

3. 完善对数据类型的检测

class ModelMetaclass(type):def __new__(cls, name, bases, attrs):mappings = dict()# 判断是否需要保存for k, v in attrs.items():# 判断是否是指定的StringField或者IntegerField的实例对象if isinstance(v, tuple):print('Found mapping: %s ==> %s' % (k, v))mappings[k] = v# 删除这些已经在字典中存储的属性for k in mappings.keys():attrs.pop(k)# 将之前的uid/name/email/password以及对应的对象引用、类名字attrs['__mappings__'] = mappings  # 保存属性和列的映射关系attrs['__table__'] = name  # 假设表名和类名一致return type.__new__(cls, name, bases, attrs)class User(metaclass=ModelMetaclass):uid = ('uid', "int unsigned")name = ('username', "varchar(30)")email = ('email', "varchar(30)")password = ('password', "varchar(30)")# 当指定元类之后,以上的类属性将不在类中,而是在__mappings__属性指定的字典中存储# 以上User类中有 # __mappings__ = {#     "uid": ('uid', "int unsigned")#     "name": ('username', "varchar(30)")#     "email": ('email', "varchar(30)")#     "password": ('password', "varchar(30)")# }# __table__ = "User"def __init__(self, **kwargs):for name, value in kwargs.items():setattr(self, name, value)def save(self):fields = []args = []for k, v in self.__mappings__.items():fields.append(v[0])args.append(getattr(self, k, None))args_temp = list()for temp in args:# 判断入如果是数字类型if isinstance(temp, int):args_temp.append(str(temp))elif isinstance(temp, str):args_temp.append("""'%s'""" % temp)sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))print('SQL: %s' % sql)u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()

运行效果如下:

Found mapping: uid ==> ('uid', 'int unsigned')
Found mapping: password ==> ('password', 'varchar(30)')
Found mapping: name ==> ('username', 'varchar(30)')
Found mapping: email ==> ('email', 'varchar(30)')
SQL: insert into User (email,uid,password,username) values ('test@orm.org',12345,'my-pwd','Michael')

4. 抽取到基类中

class ModelMetaclass(type):def __new__(cls, name, bases, attrs):mappings = dict()# 判断是否需要保存for k, v in attrs.items():# 判断是否是指定的StringField或者IntegerField的实例对象if isinstance(v, tuple):print('Found mapping: %s ==> %s' % (k, v))mappings[k] = v# 删除这些已经在字典中存储的属性for k in mappings.keys():attrs.pop(k)# 将之前的uid/name/email/password以及对应的对象引用、类名字attrs['__mappings__'] = mappings  # 保存属性和列的映射关系attrs['__table__'] = name  # 假设表名和类名一致return type.__new__(cls, name, bases, attrs)class Model(object, metaclass=ModelMetaclass):def __init__(self, **kwargs):for name, value in kwargs.items():setattr(self, name, value)def save(self):fields = []args = []for k, v in self.__mappings__.items():fields.append(v[0])args.append(getattr(self, k, None))args_temp = list()for temp in args:# 判断入如果是数字类型if isinstance(temp, int):args_temp.append(str(temp))elif isinstance(temp, str):args_temp.append("""'%s'""" % temp)sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))print('SQL: %s' % sql)class User(Model):uid = ('uid', "int unsigned")name = ('username', "varchar(30)")email = ('email', "varchar(30)")password = ('password', "varchar(30)")u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/456744.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

移动互联网广告 - 第十更 - 广告投放运营 DashBoard - 2016/12/10

广告投放运营 DashBoard设计 移动互联网互联网广告投放,数据监控DashBoard,基础样例示意,下图仅供参考(来自于互联网)。 转载于:https://www.cnblogs.com/pythonMLer/p/6154700.html

微信小程序中使用emoji表情相关说明

2019独角兽企业重金招聘Python工程师标准>>> 本帖将聚合一些跟emoji表情有关的知识;相关文章:“i爱记账” 小程序后端开发小结 第7条经验前端传过来的昵称和备注信息一定要经过严格的正则表达式过滤,放置出现XSS等攻击&#xff0c…

java.lang.IllegalArgumentException: Does not contain a valid host:port authority: ignorethis

执行Hive语句运行MapReduce程序时突然出现这样的异常: Total MapReduce jobs 1 Launching Job 1 out of 1 Number of reduce tasks not specified. Estimated from input data size: 1 In order to change the average load for a reducer (in bytes):set hive.ex…

Oracle基础语句

1、创建表create table IT_EMPLOYEES(ENPLOYEES_ID NUMBER(6) NOT NULL UNIQUE,FIRST_NAME VARCHAR2(20),LAST_NAME VARCHAR2(25) NOT NULL,EMAIL VARCHAR2(25),PHONE_NUMBER VARCHAR2(20),JOB_ID VARCHAR2(10),SALARY NUMBER(8,2),MANAGER_ID NUMBER(6));2、--创建索引&#x…

Linux三剑客之grep 与 egrep

grep:Linux上文本处理三剑客1 grep:文本过滤(模式:pattern)工具; *(grep, egrep, fgrep) 2 sed:stream editor,文本编辑工具; 3 awk:Linux上的实现gawk,文本报…

WSGI直观形象的了解一下

1. 浏览器请求动态页面过程 2. WSGI 怎么在你刚建立的Web服务器上运行一个Django应用和Flask应用,如何不做任何改变而适应不同的web架构呢? 在以前,选择 Python web 架构会受制于可用的web服务器,反之亦然。如果架构和服务器可以…

安装Hbase(分布式)遇到一些问题及解决方法

问题一:安装完成后在Hbase shell 命令行执行list命令时,爆出如下错误: hbase(main):001:0> list TABLE …

安装MySql卡在Start Service的问题

我的情况:之前在windows下安装过5.6版本,卸载后,现在安装5.7版本,然后卡在Start Service这里,log日志没报任何错误,后来经过不断的尝试各种网上的办法终于把问题解决了。 问题的原因就是当初卸载5.6版本时…

学习进度条11

第十三周 日期 星期一 星期二 星期三 星期四 星期五 星期六 所花时间(包括上课) 19:10-22:20 (编程河北省科技信息通用调查系统) 8:00-10:00 (上课) 18:30-21:00 (Oracle实验) 14:00-16:30 (编程河北省科技信息通用调查系统) 18:20-22:30 (编…

Python面向切面编程是什么

简而言之就是装饰器 https://blog.csdn.net/qq_41856814/article/details/90146293

hibernate实现多变联合查询

Hibernate主要支持两种查询方式:HQL查询和Criteria查询。前者应用较为广发,后者也只是调用封装好的接口。 现在有一个问题,就是实现多表连接查询,且查询结果集不与任何一个实体类对应,怎么解决呢? 举个例子…

PyCharm光标变粗的解决办法

pycharm中光标变粗,如下: 此时变成了改写模式,只需要按下键盘的insert键即可 转载于:https://www.cnblogs.com/uglyliu/p/6159839.html

SparkRDD常用算子实践(附运行效果图)

目录1、简单算子说明2、复杂算子说明 目录 SparkRDD算子分为两类:Transformation与Action. Transformation:即延迟加载数据,Transformation会记录元数据信息,当计算任务触发Action时,才会真正开始计算。 Action&am…

six库是什么

Utilities for writing code that runs on Python 2 and 3”“” 它是一个专门用来兼容 Python 2 和 Python 3 的库。它解决了诸如 urllib 的部分方法不兼容, str 和 bytes 类型不兼容等“知名”问题。

Kali-linux使用Nessus

Nessus号称是世界上最流行的漏洞扫描程序,全世界有超过75000个组织在使用它。该工具提供完整的电脑漏洞扫描服务,并随时更新其漏洞数据库。Nessus不同于传统的漏洞扫描软件,Nessus可同时在本机或远端上遥控,进行系统的漏洞分析扫描…

HDFS读写数据的原理

目录1 概述2 HDFS写数据流程3 HDFS读数据流程 目录 最近由于要准备面试,就把之前学过的东西好好整理下,权当是复习。 下面说下HDFS读写数据的原理。 1 概述 HDFS集群分为两大角色:NameNode、DataNode NameNode负责管理整个文件系统的元数…

理解列存储索引

版权声明:原创作品,谢绝转载!否则将追究法律责任。 优点和使用场景 SQL Server 内存中列存储索引通过使用基于列的数据存储和基于列的查询处理来存储和管理数据。 列存储索引适合于主要执行大容量加载和只读查询的数据仓库工作负荷…

Django项目部署到阿里云服务器上无法发送邮件STMP

部署好项目之后发送邮件无法发送,多方查阅之后,解决问题。 阿里云服务器禁用了25端口,导致无法发送邮件。 25端口申请开放的难度很大,直接放弃。 解决: 在 django项目的 settings.py文件中x修改port端口 。

美国诚实签经验——IMG全球医疗险,TODO

那么,诚实签最关键的4个要点 是什么呢? 第一,证明你有一定的经济实力。 可能需要房产、存款等证明,也需要银行信用卡或借记卡半年流水证明(让人信服的每月进帐和消费能力)。 这些是为了证明,你可…

大数据开发初学者学习路线

目录前言导读:第一章:初识Hadoop第二章:更高效的WordCount第三章:把别处的数据搞到Hadoop上第四章:把Hadoop上的数据搞到别处去第五章:快一点吧,我的SQL第六章:一夫多妻制第七章&…