首先見代碼:
#!/usr/bin/env python3
# encoding: utf-8
# @File: __init__.py.py
# @Author : Leon Chu <[email protected]>
# @Time : 2019-03-15 15:45
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)
class IntegerField(Field):
def __init__(self, name):
super(IntegerField, self).__init__(name, "bigint")
class StringField(Field):
def __init__(self, name):
super(StringField, self).__init__(name, "varchar(20)")
class ModelMetaclass(type):
def __new__(mcs, name, bases, attrs):
if name == "Model":
return type.__new__(mcs, name, bases, attrs)
print("Found Model:%s" % name)
mappings = dict() # 將類定義的屬性保存到dict
for k, v in attrs.items():
# 如果有定義的屬性
if isinstance(v, Field):
print("Found mappings:%s --> %s" % (k, v))
mappings[k] = v
for k in mappings.keys():
attrs.pop(k)
attrs['__mappings__'] = mappings # 保存屬性和列的映射關係
attrs['__table__'] = name # 假設表名和類名一致
res = type.__new__(mcs, name, bases, attrs)
print(res.__dict__)
return res
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): # set
self[key] = value
def save(self): # 保存
fields = []
params = []
args = []
# 這裏通過__mappings__拿到了子類的屬性
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))
def delete(self): # 刪
# 連接數據庫驅動即可真正連接
sql = "delete from %s" % self.__table__
print('SQL: %s' % sql)
def update(self): # 改
fields = []
params = []
args = []
for k, v in self.__mappings__.items():
fields.append(v.name)
params.append('?')
args.append(getattr(self, k, None))
# 連接數據庫驅動即可真正連接
sql = "update %s set %s=%s" % (self.__table__, ','.join(fields), ','.join(params))
print('SQL: %s' % sql)
print('ARGS: %s' % str(args))
def find(self): # 查
# 連接數據庫驅動即可真正連接
sql = "select * from %s" % self.__table__
print('SQL: %s' % sql)
class User(Model):
id = IntegerField("id")
username = StringField("username")
password = StringField("password")
email = StringField("email")
if __name__ == '__main__':
u = User()
u.id = 1
u.save()
接下來一步步解析
首先 我們如果要編寫orm框架,想到的一定是學一個牛逼的父類,活都扔給他幹,然後用子類繼承他,以獲得他的能力
這裏 Model 就是這個父類
接下來的問題是如何讓父類具有這個能力,即操作數據庫的能力,這個不難,而難的是他需要把這些能力都傳遞給繼承他的類
本例子中;即 ModelMetaclass
他做了幾件事情
在ModelMetaclass中,一共做了幾件事情:
一,排除掉對Model類的修改;
二,在當前類(比如User)中查找定義的類的所有屬性,如果找到一個Field屬性,就把它保存到一個__mappings__的dict中,同時從類屬性中刪除該Field屬性,否則,容易造成運行時錯誤(實例的屬性會遮蓋類的同名屬性);
三,把表名保存到__table__中,這裏簡化爲表名默認爲類名。
即做到了在父類中操作子類