欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

优酷项目之 ORM(数据库对象关系映射)代码重写

程序员文章站 2022-10-05 21:40:47
前言: 我们在操作数据库时候一般都是通过sql代码来操作mysql数据库中相关数据,这就需要懂得sql语句,那么怎么样才能在不懂sql语句的情况下通过我们所学的python代码来实现对mysql数据库的操作? 当然有这种神奇的操作,其中之一就是今天深入了解的ORM对象关系映射(Object Rela ......

前言:

  我们在操作数据库时候一般都是通过sql代码来操作mysql数据库中相关数据,这就需要懂得sql语句,那么怎么样才能在不懂sql语句的情况下通过我们所学的python代码来实现对mysql数据库的操作?

  当然有这种神奇的操作,其中之一就是今天深入了解的orm对象关系映射(object relational mapping),本文主要通过python代码来自己实现mysql数据库的对象关系映射,达到对前面所学知识的巩固与加深。

一、先来说说具体映射关系:(记住这个关系,在后面具体代码实现的时候会用到)

orm:对象关系映射:
类     =======>     数据库的一张表
对象      =======>     表的一条记录
对象点属性    =======>    记录某一个字段对应的值
上面关系分析:
通过python中创建类来实现对数据库一张表结构的关系产生一种一一对应关系
通过python中对创建的类实例化的对象操作对数据库一张表进行表记录的操作的一一对应关系
通过python中对象点属性的方式来操作记录表中某一字段的对应值,的一一对应操作关系

首先来通过代码层面来映射数据库表字段的类型:

# 定义一个类,在映射数据库中的表结构:
class field(object): 
    #  先定义一个表结构字段类,比如 字段名name、字段类型column_type、字段是否为主键primary_key、字段默认值default
    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
    
#  当然字段的类型很多,可以单独设特殊的字段类:比如varchar、int字段类型,让它继承field类就行
class stringfield(field):  #  定义字段类型varchar
    #  将字段类型指定为:varchar(255),主键默认为false,默认值为none
    def __init__(self, name, column_type='varchar(255)', primary_key=false, default=none):
        #  让它重写__init__的基础上其他地方继承它的基类field里面的__init__方法
        super().__init__(name, column_type, primary_key, default)
        
class integerfield(field):  # 定义字段类型int
    def __init__(self, name, column_type='int', primary_key=false, default=none):
        super().__init__(name, column_type, primary_key, default)

暂时先创建2种常见类型的字段类型类

接着来看看如何映射数据库表的结构:

# 创建一个字典对象的过程:t1 = dict(name='sgt', age=18, sex = 'male')
# 让models类继承字典这个类,这样models类就继承了dict类的方法(把一堆关键字参数传进去,返回一个字典)的实例化过程
class models(dict):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
    
    # 除了继承dict类的方法,我们还需要拥有更多方法,比如当传入的参数通过对象点(传入参数关键字名)的方法得到参数的
    # 关键字值,通过点参数名=参数值来新增传入的关键字参数
    # 继续分析:传入参数是关键字形式(name='sgt',age = 18...),但是参数不是类中属性,如果想要通过实例化出的对象点
    # 这个参数key的方式得到value值的目的,可以使用__getattr__来实现,也就是说,实例化出的对象在点这个key
    # 时候,触发了__getattr__方法,方法返回self.get(key),这里的self就是继承dict类通过传入关键字参数返回的字典
    # 类型的的对象,通过点get()就能获得对应的value值。
    def __getattr__(self, item):  # 在对象获取它没有的属性和方法的时候触发
        return self.get(item)  # item就是传入参数的k
    
    # 既然可以点k的方式得到value,那么还可以点新key=值的方法来增加传入的关键字参数
    def __setattr__(self, key, value):  # 在对象点属性=值的时候自动触发
        self[key] = value
        
    # 通过上面的__getattr__和__setattr__的方法实现了实例化出对象的方式让传入的参数返回给对象一个字典的
    # 同时又可以让这个对象点关键字中的key得到value值,点key=value值来新增或者设置值的目的
    # 这里插一嘴:为何要实现这个目的?因为我们通过pymysql模块实现操作数据库返回来的数据类型基本都是字典类型外面
    # 套列表的形式,那么如果想办法将查询的结果也变成一个字典对象,那么查询里面的key(字段名)和value(字段记录值)
    # 就特别方便了,同时在新增和插入数据时候会用到这个方法,达到更简单明了的目的。

  上面只是实现了我么在操作表记录方面的某些功能,但是我么知道还没有达到映射数据库表结构的目的

  怎么做呢?想想我们的目的:在映射表结构的时候这个表结构应该有哪些东西?

  回答:表的字段名们,表的主键是哪个字段,当然还有表名,好像有了这3个关键性的因素映射数据库表结构就差不多达到目的了。

  那么如何才能实现我们在创建一个映射表结构的一个类的同时这些我们想要的因素都能自动产生呢?

说到自动,又说道创建类的时候,我想我们可以往元类上面想了,前面学习元类的时候我们就可以拦截类的创建过程,在这个过程中加入或者修改,达到我们想要的目的。

  所以说拦截类的创建过程是关键,类创建过程会触发啥?答案是:元类的__new__方法

既然要拦截,肯定是不让元类的__new__生效,让我们自己定义一个__new__或者说在元类的__new__触发之前自己通过自定义__new__来加入一些我们需要的然后再走元类的__new__,此时就能达到目的了。

想法很好,一步一步