前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

orm

作者头像
GH
发布2019-12-12 17:28:50
5870
发布2019-12-12 17:28:50
举报
文章被收录于专栏:python、mysql、go知识点积累

orm

对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示着额外的执行开销;然而,如果ORM作为一种中间件实现,则会有很多机会做优化,而这些在手写的持久层并不存在。 更重要的是用于控制转换的元数据需要提供和管理;但是同样,这些花费要比维护手写的方案要少;而且就算是遵守ODMG规范的对象数据库依然需要类级别的元数据。

在对orm进行架构时首先要分清数据库和对象之间的映射关系:

对象与类

数据库

类名

表名

对象

一条记录

对象.属性

字段

这里将数据库的增删改查全部封装为一个个的方式,比如:save,delete,update,select等

具体思路:

一、数据类型类的定义

对字段可能用到的数据类型创建类,然后将这些类实例化出的对象作为字段类的属性。

抽象出父类

代码语言:javascript
复制
class Field:
    def __init__(self,name,column_type,primary_key,default):
        self.name = name
        self.column_type = column_type
        self.primary_key = primary_key
        self.default = default

子类

代码语言:javascript
复制
class IntegerField(Field):
    def __init__(self,name,column_type='int',primary_key=False,default=0):
        super().__init__(name,column_type,primary_key,default)

class StringField(Field):
        def __init__(self,name,column_type='varchar(64)',
                     primary_key=False,default=None):
            super().__init__(name,column_type,primary_key,default)

二、定义表类

抽象出表的父类,这里表类继承字典是为了解决每一张表可以随意添加字段的问题,我们不能每实例化一张表就在表类的__init__中定义新添加的字段名,这样太麻烦了。通过继承字典,内部的__init__,可以接收任意多个关键字参数。

代码语言:javascript
复制
class Models(dict,metaclass=OrmMetaclass):
    def __getattr__(self, item):
        #调用没有的属性时触发
        return self.get(item)

    def __setattr__(self, key, value):
        #实现将对象.属性=属性值转化为字典的赋值操作
        #给字典对象本身赋值
        self[key] = value

子类

代码语言:javascript
复制
class User(Models):
    #属性名最好与字段类型的名字同名
    user_id = IntegerField(name='user_id',primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='pwd')
    #这些属性都是字段类型类实例化出来的

class Movie(Models):
    user_id = IntegerField(name='user_id',primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='pwd')

三、引入元类

继承字典的类实例化的对象,无法通过‘对象.属性’的方式存取值,我们通过__setattr__,__getattr__来实现,让字典对象与普通对象一模一样,并且具备字典对象原有的特性。

元类需要处理的问题:

  1. 强制数据表类有且只有一个主键。
  2. 将数据表中所有的字段对象都存放在一个独立的字典中,方便取用。
代码语言:javascript
复制
'''__new__必须要有返回值,返回实例化出来的实例,
        这点在自己实现__new__时要特别注意,
        可以return父类__new__出来的实例,
        或者直接是object的__new__出来的实例'''
class OrmMetaclass(type):
    def __new__(cls, class_name,class_base,class_dict):
        #class_base:类名(表名)class_base:基类/父类 class_dict:类的名称空间
        
        #过滤Models类,如果输入的是Models类,直接将类返回
        if class_name == 'Models':
            return type.__new__(cls,class_name,class_base,class_dict)
        table_name = class_dict.get('table_name',class_name)
        #获取table_name如果table_name不存在,就获取class_name
        primary_key = None
        定义一个空的字典,专门用来存放字段对象
        mappings = {}
        
        遍历名称空间所有的属性
        print(class_dict)
        '''
               {'__module__': '__main__', '__qualname__': 'User',
                'user_id': <__main__.IntegerField object at 0x000001C3E13FA7B8>,
                 'user_name': <__main__.StringField object at 0x000001C3E13FA7F0>,
                  'pwd': <__main__.StringField object at 0x000001C3E13FA828>}
        '''
        #这里的每一个字段属性都是对应的字段类实例化出的对象
        #key是对象名,value是对象地址

        #遍历类的名称空间的所有属性
        for key,value in class_dict.items():

            #判断value是否是Field 实例化的对象,
            # Field是所有字段的父类
            if isinstance(value,Field):

                #将属性和名称放入mappings字典里
                mappings[key] = value

                if value.primary_key:
                    #判断实例化出来的字段的主键属性是否为true

                    #如果primary_key有值,则已经有一个字段的primary_key属性
                    #设置为了True
                    if primary_key:
                        raise TypeError('只能有一个主键')

                    #如果该字段是主键,就将主键名赋值给primary_key
                    primary_key = value.name

        for key in mappings.keys():
            class_dict.pop(key)

        #给类的名称空间添加表名
        class_dict['table_name'] = table_name

        #给类的名称空间添加主键名
        class_dict['primary_key'] = primary_key

        #给类的名称空间添加mapping字典,字典中拥有所有的字段属性
        class_dict['mappings'] = mappings
        return type.__new__(cls,class_name,class_base,class_dict)
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-11-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、数据类型类的定义
  • 二、定义表类
  • 三、引入元类
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档