ORM全称“Object Relational Mapping”,即对象-关系映射,就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样,写代码更简单,不用直接操作SQL语句。
要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
让我们来尝试编写一个ORM框架。
编写底层模块的第一步,就是先把调用接口写出来。比如,使用者如果使用这个ORM框架,想定义一个User类来操作对应的数据库表User,我们期待他写出这样的代码:
期望代码
class User(Model): # User类,继承Model
# 定义类的属性到列的映射: 右边的 StringField(‘username’),这里StringField是类,类(‘username’)是输入__init__绑定的参数,所以得到的是一个实例,正好对应value
id = IntegerField('id') # ⚠️id理解为一个变量不好,id理解成一个key最恰当,=右边的则是value,这里对应的就是数据库字典的id数据
name = StringField('username') # name是类属性,具体可参考类属性与实例属性定义,类调用属性就是User.name
email = StringField('email') # id name email password 均是User的属性,User的实例可以直接调用
password = StringField('password') # User().name = StringField(‘username’),直接调用,也就是对应一个user的表,表里的name叫SF()
# 创建一个实例:
u = User(id=12345, name='Michael', email='test@orm.org', password='my-pwd') # ⚠️对照这个效果可以想通一二了
# 保存到数据库:
u.save()
其中,父类Model和属性类型StringField、IntegerField是由ORM框架提供的,剩下的魔术方法比如save()全部由metaclass自动完成。虽然metaclass的编写会比较复杂,但ORM的使用者用起来却异常简单。
现在,我们就按上面的接口来实现该ORM。
首先来定义Field类,它负责保存数据库表的字段名和字段类型
class Field(object): # 对应数据库中保存的字段名和字段类型
def __init__(self, name, column_type): # 添加__init__(self,name)方法后,类的实例必须是StringField(‘某name’),正好呼应上方的期望代码
self.name = name # 字段名
self.column_type = column_type # 字段类型
def __str__(self): # 输入print(xxx)会自动调用__str__,它为了使打印结果更好看而已,Python 定义了__str__()和__repr__()两种方法,__str__()用于显示给用户,而__repr__()用于显示给开发人员。
return '' % (self.__class__.__name__, self.name) # 不使用print(xxx)而是直接输入实例xxx,则该行不会打印显示出来,看起来就很丑
在Field的基础上,进一步定义各种类型的Field,比如StringField,IntegerField等等:
class StringField(Field): # ✌️通过比对测试,StringField.name = name, StringField.column_type = varchar(100).
def __init__(self, name): # 实例属性,`实例.name`调用
super(StringField, self).__init__(name, 'varchar(100)') # 为什么这么设计?super最后跟的参数是(name,’varchar(100)’)一个变量name