在学习django的使用过程中,发现ORM是个好东西,不需要自己去数据库创建表,也不需要写sql语句,就可以实现对数据库的增、删、查、改,于是就想,ORM的是怎么实现的呢?经过两天的努力一个小demo被我成功的“写”出来了。
(参考来自:https://blog.csdn.net/yang5102/article/details/52485977)
代码如下:(写的很粗鄙,中间有很多自己不懂加的注释,初学者,见谅,见谅,有不对的地方还请指出,共同进步~~~~)
首先是Field
模块,Field
类是个基类,规定数据库表的字段名称:name
与类型:type
CharField
继承Field
,并且可以输入字符长度,IntegerField
也是继承Field
。
定义Field
基类,是在元类中实例出Field
对象v
时,可以直接通过v.name
获取表的字段名。
class Field(object):
def __init__(self, name,type):
self.name = name
self.type =type
# 当打印这个类时,系统默认找类里的__str__函数去输出,
# 如果没有这个函数,输出的就是一个对象
def __str__(self):
print ('%s:%s' % (self.__class__.__name__, self.name))
class CharField(Field):
def __init__(self, name, length=10):
self.length = length
super(CharField, self).__init__(name, 'string')
class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'Interger')
然后是Model类的编写,Model类是各种实体类的基类,如User(Model),所以公共的.save()方法,Update()方法等都封装到Model类里。:
class Model(dict):
__metaclass__ = ModelMetaclass
def __init__(self, **kw):
super(Model, self).__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Model' object has no attribute '%s'" % key)
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('%s')
args.append(getattr(self, k, None))
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
cursor.execute(sql,args)
db.commit()
print('SQL: %s' % sql)
print('ARGS: %s' % str(args))
最后是ModelMetaclass元类的代码:
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
if name == 'Model':
return type.__new__(cls, name, bases, attrs)
mapping = dict()
fields = []
params = []
keyid = []
for k, v in attrs.items():
# isinstance(对象,类)检测这个对象是否属于这个类
if isinstance(v, Field) :
# print('Found mapping :%s==>%s'% (k,v))
mapping[k] = v
for k in mapping.keys():
# pop() 方法删除字典给定键 key 所对应的值,返回值为被删除的值
attrs.pop(k)
attrs['__mappings__'] = mapping
for k, v in mapping.items():
if isinstance(v, CharField):
fields.append(v.name + ' char(%s)'% str(v.length))
elif isinstance(v, IntegerField):
fields.append(v.name + ' INT')
keyid.append(k)
attrs['__table__'] = name
sql = 'create table IF NOT EXISTS %s (%s) ' % (name, ','.join(fields))
print('SQL: %s' % sql)
try:
cursor.execute(sql)
print("create success")
except Exception as e:
print("create failure")
print('SQL: %s' % sql)
return type.__new__(cls, name, bases, attrs)
ORM实体类的创建是通过元类动态实现的,
也就是通过 :type.__new__(cls, name, bases, attrs)
实现的
cls:用来创建类的元类。
name:被创建类的名称
bases:被创建的类继承于哪些类,即被创建类的所有父类
attrs:被创建类的属性。
为什么要使用元类来创建类?而不是使用class关键字?
在python中万物皆对象,类也是对象,而元类就是类的类。
而类存在的意义就是抽象出对象共同的属性和方法。
实体类例如:User,Course......
都需要创建数据库对应的表,都需要知道表字段的名称,都需要知道表名等
所以定义的元类抽象出所有实体类共同的属性和方法,来创建类。(感觉很绕啊~~~~)
程序中元类ModelMetaclass主要做了如下几件事:
1.查找实体类(比如User
)的Field
属性(比如CharField
),找到之后保存到mapping
中,然后再把mapping
保存到attr[__mapping__]
中,这样在ModelMetaclass创建的类中就可以使用self.__mapping__
来访问自己的Field属性。
2.保存表名到attrs['__table__'] = name
中
3.根据Field
属性与表名创建同名表
创建User时程序编译的过程如下:
最后是完整的代码:
import pymysql
# 1.定义filed
# 2.拼接字符串
# 3.元类
db = pymysql.connect("localhost", "root", "root", "ormtest")
cursor = db.cursor()
class Field(object):
def __init__(self, name, type):
self.name = name
self.type = type
# 当打印这个类时,系统默认找类里的__str__函数去输出,
# 如果没有这个函数,输出的就是一个对象
def __str__(self):
print ('%s:%s' % (self.__class__.__name__, self.name))
class CharField(Field):
def __init__(self, name, length=10):
self.length = length
super(CharField, self).__init__(name, 'string')
class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, 'Interger')
# type(classname, parentclasses , attrs)
# classname是类名,字符串类型,parentclasses是类所有父类,元组类型,attrs是类的所有{属性:值}
# 当通过type.__new__(cls, classname, bases, attrs)创建类时,cls就是该类的元类,classname是类名,字符串类型,bases是类的父类,元组类型,attrs是类的所有{属性:值}
# 只有type和其子类可以用__new__创建类
class ModelMetaclass(type):
def __new__(cls, name, bases, attrs):
if name == 'Model':
return type.__new__(cls, name, bases, attrs)
print('Found model :%s' % name)
print('Found model cls :%s' % cls)
print('Found attrs :%s' % str(attrs))
mapping = dict()
fields = []
params = []
keyid = []
for k, v in attrs.items():
# isinstance(对象,类)检测这个对象是否属于这个类
if isinstance(v, Field) :
# print('Found mapping :%s==>%s'% (k,v))
mapping[k] = v
for k in mapping.keys():
# pop() 方法删除字典给定键 key 所对应的值,返回值为被删除的值
attrs.pop(k)
attrs['__mappings__'] = mapping
for k, v in mapping.items():
if isinstance(v, CharField):
fields.append(v.name + ' char(%s)'% str(v.length))
elif isinstance(v, IntegerField):
fields.append(v.name + ' INT')
keyid.append(k)
attrs['__table__'] = name
sql = 'create table IF NOT EXISTS %s (%s) ' % (name, ','.join(fields))
print('SQL: %s' % sql)
try:
cursor.execute(sql)
print("create success")
except Exception as e:
print("create failure")
print('SQL: %s' % sql)
return type.__new__(cls, name, bases, attrs)
# 只能python3用 metaclass=ModelMetaclass,python2使用__metaclass__ = ModelMetaclass
# metaclass=ModelMetaclass,当编译器要创建Model类时,要从ModelMetaclass.__new__来创建
class Model(dict):
__metaclass__ = ModelMetaclass
def __init__(self, **kw):
super(Model, self).__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Model' object has no attribute '%s'" % key)
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('%s')
args.append(getattr(self, k, None))
sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
cursor.execute(sql,args)
db.commit()
print('SQL: %s' % sql)
print('ARGS: %s' % str(args))
class User(Model):
# 定义类的属性到列的映射:
id = IntegerField('id')
name = CharField('username',100)
# 创建一个实例:
u = User(id=12345, name='Michael')
# 保存到数据库:
u.save()