Python 手写ORM-我的一个数据库访问工具(三)

第一节整体介绍了ef-python,第二节把整体集合类Collection完成了,而本节我们来完成ORM的核心,对象映射
第一节:ORM的使用Python 手写ORM-我的一个数据库访问工具(一)
第二节:Collection类的构造Python 手写ORM-我的一个数据库访问工具(二)

对DBCollection的小修饰

因为对于ORM对象,其添加对象会更加严谨,所以要禁用__iadd__add函数

DBRecord对象

class Record:
    def __init__(self, data, mainkey, sign=None):
        self.data = data
        self.sign = sign
        self.mainkey = mainkey

对于维护的数据,为了更好的查找会使用DBRecord对象去储存

内部函数

该文件中的内部函数

def findkey(source, mainkey):
    for i in source:
        if i.mainkey == mainkey:
            return i


def findsign(source):
    data = []
    for i in source:
        if i.sign is not None:
            data.append(i)
    return data


def objcmp(object1, object2):
    for i, j in zip(object1.__dict__, object2.__dict__):
        if object1.__dict__[i] != object2.__dict__[j]:
            return False
    return True

findkey函数

参数名称类型说明
sourcelist<Record>待Record集合
mainkeystring主键

返回值
索引 int

findsign

参数名称类型说明
sourceRecord待查找的Record

返回值
list<Record> 可追踪的Record

objcmp

参数名称类型说明
object1TableObject比对对象1
object2TableObject比对对象2

返回值
bool 是否相等

DBSet对象

__init__函数

DBSet对象是ORM中数据表的映射

    def __init__(self, context, table, init=None):
        self._table = table
        if init is None:
            init = context.create()
        self._cursor = init[1]
        self._conn = init[0]
        self._view = Collection()
        self._mainkey = None
        self._lines = []

        # 查找所有字段名,生成
        sqlstring = f'select COLUMN_NAME from information_schema.columns where table_name=\'{self._table}\''

        self._cursor.execute(sqlstring)
        result = list(self._cursor.fetchall())
        self._keys = []
        for key in result:
            self._keys.append(key[0])
        self._model = type(self._table, (object,), {})

        sqlstring = f'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE  WHERE  TABLE_NAME=\'{self._table}\''
        self._cursor.execute(sqlstring)
        self._mainkey = self._cursor.fetchall()[0][0]
        sqlstring = f'Select * from {self._table}'
        self._cursor.execute(sqlstring)
        result = self._cursor.fetchall()
        # 转换数据类型
        for datas in result:
            obj = self._model()
            for data, key in zip(datas, self._keys):
                obj.__dict__[key] = data
            record = Record(obj, obj.__dict__[self._mainkey])
            self._view.add(record)         
参数名类型说明
contextDBContext创建的DBContext
tablestringTable名称

代码解读

self._table = table
self._cursor = init[1]
self._conn = init[0]
self._view = Collection()
self._mainkey = None
self._lines = []
self._keys = []
self._model = type(self._table, (object,), {})

self._table用于储存表名,self._cursor和self._conn用于储存游标对象连接对象,而DBContext有一个内部方法.create()函数用于返回这两个对象进行初始化,self._view用于储存查询对象,self._mainkey储存主键,self._lines用于储存过程语句,self._key用于储存所有的字段,self._model用于储存映射表对象

该函数可以通过表名获取主键和字段来初始化,并且自动构造映射表对象然后载入对象

flush函数

    def flush(self):
        self._lines.clear()
        self._view.clear()
        sqlstring = f'Select * from {self._table}'
        self._cursor.execute(sqlstring)
        result = self._cursor.fetchall()
        # 转换数据类型
        for datas in result:
            obj = self._model()
            for data, key in zip(datas, self._keys):
                obj.__dict__[key] = data
            record = Record(obj, obj.__dict__[self._mainkey])
            self._view.add(record)

清空记录并且刷新查询

savechanges函数

    def savechanges(self):
        # 判断移出对象是否改变
        changes = findsign(self._view)
        for i in changes:
            # 修改所有的值
            if objcmp(i.data, i.sign):
                continue
            else:
                # 上传修改了的值
                data = ''
                for key, value in zip(i.data.__dict__.keys(), i.data.__dict__.values()):
                    data += f'{key}=' + f'\'{value}\'' + ','
                data = str(data).removesuffix(',')
                sqlstring = f'update {self._table} set {data} where {self._mainkey}=\'{i.sign.__dict__[self._mainkey]}\''
                self._lines.append(sqlstring)

        # 上传每一条修改语句
        for i in self._lines:
            print(i)
            self._cursor.execute(i)

        # 清除所有执行语句
        self.flush()

        self._conn.commit()

保存修改并刷新,通过对追踪对象比较现在的值和之前的值是否相同,不相同则更新,相同则跳过

where函数

    def where(self, expression):
        data = Collection()
        for item in self._view:
            if expression(item.data):
                item.sign = copy.copy(item.data)
                data.add(item.data)
        return data
参数名类型说明
expressionfunction筛选规则

find函数

    def find(self, key):
        result = self._view.where(lambda x: x.data.__dict__[self._mainkey] == key).firstordefault()
        if result is None:
            return None
        result.sign = copy.copy(result.data)
        return result.data
参数名类型说明
keystring查询的主键值

add函数

    def add(self, item):
        if type(item) != self._model:
            raise TypeError()
        else:
            self._view.add(Record(item, item.__dict__[self._mainkey]))
            data = str(tuple(item.__dict__.values())).replace('None', 'Null')
            sqlstring = f'insert into {self._table} values {data}'
            self._lines.append(sqlstring)
参数名类型说明
itemTableObject增加的对象

DBContext对象

class DBContext(object):
    def __init__(self, con):
        self._conn = con
        self._cursor = self._conn.cursor()

    def create(self):
        return self._conn, self._cursor

    def add(self, item):
        # 自分配增加对象
        for dbset in self.__dict__.values():
            if type(dbset) is DBSet:
                if dbset.__dict__['_model'] is type(item):
                    dbset.add(item)
                    return
        raise Exception('Error Could Not Find DBSet')

    def savechanges(self):
        for dbset in self.__dict__.values():
            if type(dbset) is DBSet:
                dbset.savechanges()

    def execute(self, sqlstring):
        self._cursor.execute(sqlstring)
        result = self._cursor.fetchall()
        self._conn.commit()
        return result

    def close(self):
        self._cursor.close()
        self._conn.close()
        del self

基DBContext对象,编写自己的上下文对象是需继承该对象

点击下载全文代码

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纸墨青鸢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值