简易django ORM模型如下所示:

#!/usr/bin/env python
# encoding: utf-8
"""
@version: 1.0
@author: Pis
@license: Apache Licence
@software: PyCharm
@file: orm_test.py
@time: 2018/5/9 9:52
""" #1
class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type def __str__(self):
return '<%s:%s>' % (self.__class__.__name__, self.name) #2
class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, 'varchar(100)') #3
class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'bigint') #4
# 下一步,就是编写最复杂的ModelMetaclass了:
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
if name == 'Model': # 排除掉对Model类的修改;
return type.__new__(cls, name, bases, attrs)
print('Found Model: %s' % name)
mappings = dict()
for k, v in attrs.items(): # 查找定义的类的所有属性,
if isinstance(v, Field): # 如果找到一个Field属性,
print('Found mapping: %s ==> %s' % (k, v))
mappings[k] = v # 就把它保存到一个__mappings__的dict中
for k in mappings.keys():
attrs.pop(k) # 同时从类属性中删除该Field属性,否则,容易造成运行时错误(实例的属性会遮盖类的同名属性);
attrs['__mappings__'] = mappings # 保存属性和列的映射关系
attrs['__table__'] = name # 假设表名和类名一致 把表名保存到__table__中
return type.__new__(cls, name, bases, attrs) #5
# 基类Model
class Model(dict, metaclass=ModelMetaclass):
def __init__(self, **kw):
super(Model, self).__init__(**kw) def __getattr__(self, item): # 没有找到的属性,就在这里找
try:
return self[item]
except KeyError:
raise AttributeError(r"'Model' object has no attrs :'%s'" % item) def __setattr__(self, key, value):
self[key] = value def save(self):
fields = []
params = []
args = []
for k, v in self.__mappings__.items():
fields.append(v.name)
params.append('?')
args.append(getattr(self, k, None))
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
print('SQL: %s' % sql)
print('ARGS: %s' % str(args)) # 子类User

#6
# 定义类的属性到列的映射:
class User(Model):
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
age = IntegerField('age')

#7
if __name__ == "__main__":
u = User(id=12345, name='john', email='123456789@qq.com', password='666666', height="top")
u.age = 12
u.save()

 

在代码执行过程中,在执行#7之前,首先是class的创建,在没有标明metaclass的情况下默认是由type通过__new__创建class对象,在标明了metaclass的情况下由metaclass的__new__方法创建(关于metaclass 的查找顺序上一篇给出【self,parents,local】),class创建完毕后才开始#7的执行,由于User类没有构造__new__和__init__方法,且User的父类Model继承了dict类,所以当height字段不在User的attrs时依然不会报错,实际上输入任何的关键字参数都不会出错。ORM模型在u.save()时,是通过查找在__new__时__map__中的字段,也就是#6中的(id,name,email,password,age),通过sql语句动态的执行存储操作。

通过ORM模型看python对象创建过程的更多相关文章

  1. 【原创】Python 对象创建过程中元类, __new__, __call__, __init__ 的处理

    原始type: type是最原始的元类,其__call__方法是在你使用" t_class = type(classname_string, base_classes_tuple, attr ...

  2. Java中对象创建过程

    本文介绍的对象创建过程仅限于普通Java对象,不包括数组和Class对象. 1.类加载检查 虚拟机遇到一条new指令时,首先去检查该指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用 ...

  3. Java中类加载过程和对象创建过程

    类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在.如果有,就直接使用:如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加 ...

  4. java基础---类加载和对象创建过程

    类中可以存在的成员: class A{ 静态成员变量: 非静态成员变量: 静态函数: 非静态函数: 构造函数 A(..){...} 静态代码块 static{...} 构造代码块 {...} } 类加 ...

  5. COM对象创建过程

    在客户端需要调用COM组件时,通常调用windowAPI函数: STDAPI CoCreateInstance( REFCLSID rclsid, //创建的Com对象的类标识符(CLSID) LPU ...

  6. java类加载、对象创建过程

    类加载过程: 1, JVM会先去方法区中找有没有相应类的.class存在.如果有,就直接使用:如果没有,则把相关类的.class加载到方法区 2, 在.class加载到方法区时,会分为两部分加载:先加 ...

  7. JBPM TaskInstance 对象创建过程

    对象获得过程如下: 获得对象工厂--->工厂创建代理对象 TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance(); TaskI ...

  8. Java内存区域与对象创建过程

    一.java内存区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有的区域则 ...

  9. OC对象创建过程

    在利用OC开发应用程序中,须要大量创建对象,那么它的过程是什么呢? 比方:NSArray *array = [[NSArrayalloc] init]; 在说明之前,先把OC的Class描写叙述一下: ...

随机推荐

  1. Restful风格wcf调用

    文章:Restful风格wcf调用 作者相当于把wcf服务改造成rest风格. Restful风格wcf调用2——增删改查 这篇文章在第一篇的基础上,进行了优化. Restful风格wcf调用3——S ...

  2. java核心技术卷1知识点

    1.comparable和comparator的区别. Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较的. public inte ...

  3. iOS成长之路-使用系统默认声音、震动

    导入框架 代码片段 apple系统默认声音名称说明: 1.声音格式是MP3或m4r的需要转成caf格式(可先转成aif , aiff,然后修改后缀) 2.路径在/System/Library/Audi ...

  4. sprintf函数 %6.2f

    %6.2f6表示数据表示至少6位,后面的.2表示小数点后保留两位 比如2342.123415用这个表示的话,结果就是2342.12如果不足六位就会在前面补空格超过六位的话正常显示 代码例子:int m ...

  5. 解决java使用Runtime.exec执行linux复杂命令不成功问题

    最近要实现一个Java调用一个复杂shell命令实现数据同步,该命令有管道重定向的语句,结果硬是执行不成功,而且也没异常报出.经过一段时间的折腾终于解决了此问题,权当做备忘记录下来(重点在红色框中的“ ...

  6. PAT 甲级 1112 Stucked Keyboard

    https://pintia.cn/problem-sets/994805342720868352/problems/994805357933608960 On a broken keyboard, ...

  7. c++ 替换修改一个文件夹下的所有文件的文件名

    代码简洁,亲测可用. 1,首先来获取(输出)一个文件夹中所有的文件名 void getFiles(string path, vector<string>& files) { //文 ...

  8. Django知识总汇

    基础 Django基础 Django基本命令 model系统 ORM基础 ORM字段和参数 ORM对数据库操作 ORM中介模型 ORM之其他骚操作 templates系统 模板语言 views系统 视 ...

  9. Logrotate还有谁记得它??

    我发现很多人的服务器上都运行着一些诸如每天切分Nginx日志之类的CRON脚本,大家似乎遗忘了Logrotate,争相发明自己的轮子,这真是让人沮丧啊!就好比明明身边躺着现成的性感美女,大家却忙着自娱 ...

  10. Delphi 判断一个字符串是否为数字

    //函 数 名: IsDigit//返 回 值: boolean//日       期:2011-03-01//参       数: String//功       能: 判断一个字符串是否为数字// ...