python小技巧大应用--实现自己的SQLite3 ORM(全)

上篇文章初步实现了SQLite3 ORM查询功能,经过一周多的努力,终于将SQLite3的CRUD全部功能实现了ORM.这回只上代码,实现示例及实现结果,其他相关内容请参见我的相关文章

1.建立uitl_SQLiteORM.py工具模块

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__ = 'TianJiang Gui'

import asyncio, logging

import sqlite3
#---gtj 设置log输出格式
logging.basicConfig(format='%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s',
                        level=logging.INFO)
# ---gtj sqlite数据库文件名
db = 'sqlite-data.db'

def log(sql, args=()):
    logging.info('SQL: %s' % sql)
    # logging.info('SQL: %s' % sql.replace('?', '%s'), args or ())

# 返回字典方法,传入一个执行过查询sql语句的cursor对象
def dict_factory(cursor, row):
    d = {}
    for idx, col in enumerate(cursor.description):
        d[col[0]] = row[idx]
    return d

def db_Select(sql, args, size=None):
    log(sql, args)
    connect = sqlite3.connect(db)
    connect.row_factory = dict_factory
    cursor = connect.cursor()
    try:
        cursor.execute(sql,args)
        rs = cursor.fetchall()  # 获取查询结果 sqlite_dict(cursor)#
        rows = len(rs)
        logging.info('rows returned: %s' % rows)
    except Exception as e:
        print(u'查询错误...', e)
        connect.rollback()
    finally:
        cursor.close()
        connect.close()
    return rs

def db_Instert(sql, args, autocommit=True):
    log(sql,args)
    connect = sqlite3.connect(db)
    cursor = connect.cursor()
    try:
        cursor.execute(sql, args)
        connect.commit()
        print(u'插入成功影响行数1')
    except Exception as e:
        print(u'插入错误...', e)
        connect.rollback()
    finally:
        cursor.close()
        connect.close()
    return 1

def db_Update(sql, args, autocommit=True):
    log(sql,args)
    connect = sqlite3.connect(db)
    cursor = connect.cursor()
    try:
        cursor.execute(sql, args)
        rows = cursor.rowcount
        print("待更新行数:" + str(rows))
        connect.commit()
        print(u'修改成功...')
    except Exception as e:
        print(u'插入错误...', e)
        connect.rollback()
    finally:
        cursor.close()
        connect.close()
    return 1

# ---gtj 删除
# delete_sql = "DELETE from userinfo WHERE `name` = 'gtj2'"
def db_Delete(sql, args, autocommit=True):
    log(sql,args)
    connect = sqlite3.connect(db)
    cursor = connect.cursor()
    try:
        cursor.execute(sql,args)
        rows = cursor.rowcount
        logging.info('rows returned: %s' % rows)
        print("待删除行数:" + str(rows))
        connect.commit()
        print(u'删除成功...')
    except Exception as e:
        print(u'删除错误...', e)
        connect.rollback()
    finally:
        cursor.close()
        connect.close()
    return 1




def create_args_string(num):
    L = []
    for n in range(num):
        L.append('?')
    return ', '.join(L)

class Field(object):

    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

    def __str__(self):
        return '<%s, %s:%s>' % (self.__class__.__name__, self.column_type, self.name)
        # return '<%s:%s>' % (self.__class__.__name__, self.name)

class StringField(Field):

    def __init__(self, name=None, primary_key=False, default=None, ddl='varchar(100)'):
        super().__init__(name, ddl, primary_key, default)

class BooleanField(Field):

    def __init__(self, name=None, default=False):
        super().__init__(name, 'boolean', False, default)

class IntegerField(Field):

    def __init__(self, name=None, primary_key=False, default=0):
        super().__init__(name, 'bigint', primary_key, default)

class FloatField(Field):

    def __init__(self, name=None, primary_key=False, default=0.0):
        super().__init__(name, 'float', primary_key, default)

class TextField(Field):

    def __init__(self, name=None, default=None):
        super().__init__(name, 'text', False, default)

class ModelMetaclass(type):
    def __new__(cls, name, bases, attrs):
        if name=='Model':
            return type.__new__(cls, name, bases, attrs)
        tableName = attrs.get('__table__', None) or name
        logging.info('found model: %s (table: %s)' % (name, tableName))
        mappings = dict()
        fields = []
        primaryKey = None
        for k, v in attrs.items():
            if isinstance(v, Field):
                logging.info('  found mapping: %s ==> %s' % (k, v))
                mappings[k] = v
                if v.primary_key:
                    # 找到主键:
                    if primaryKey:
                        raise Exception('Duplicate primary key for field: %s' % k)
                    primaryKey = k
                else:
                    fields.append(k)
        if not primaryKey:
            raise Exception('Primary key not found.')
        for k in mappings.keys():
            attrs.pop(k)
        escaped_fields = list(map(lambda f: '`%s`' % f, fields))
        attrs['__mappings__'] = mappings # 保存属性和列的映射关系
        attrs['__table__'] = tableName
        attrs['__primary_key__'] = primaryKey # 主键属性名
        attrs['__fields__'] = fields # 除主键外的属性名
        attrs['__select__'] = 'select `%s`, %s from `%s`' % (primaryKey, ', '.join(escaped_fields), tableName)
        attrs['__insert__'] = 'insert into `%s` (%s, `%s`) values (%s)' % (tableName, ', '.join(escaped_fields), primaryKey, create_args_string(len(escaped_fields) + 1))
        attrs['__update__'] = 'update `%s` set %s where `%s`=?' % (tableName, ', '.join(map(lambda f: '`%s`=?' % (mappings.get(f).name or f), fields)), primaryKey)
        attrs['__delete__'] = 'delete from `%s` where `%s`=?' % (tableName, primaryKey)
        return type.__new__(cls, name, bases, attrs)

class Model(dict, metaclass=ModelMetaclass):

    def __init__(self, **kw):
        super(Model, self).__init__(**kw)

    def __getattr__(self, key):
        try:
            print('gtj key %s==>%s' % (key, self[key]))
            return self[key]
        except KeyError:
            raise AttributeError(r"'Model' object has no attribute '%s'" % key)

    def __setattr__(self, key, value):
        self[key] = value


    def getValue(self, key):
        return getattr(self, key, None)

    def getValueOrDefault(self, key):
        value = getattr(self, key, None)
        if value is None:
            field = self.__mappings__[key]
            if field.default is not None:
                value = field.default() if callable(field.default) else field.default
                logging.debug('using default value for %s: %s' % (key, str(value)))
                setattr(self, key, value)
        return value

    @classmethod
    def findAll(cls, where=None, args=None, **kw):
        ' find objects by where clause. '
        sql = [cls.__select__]
        if where:
            sql.append('where')
            sql.append(where)
        if args is None:
            args = []
        orderBy = kw.get('orderBy', None)
        if orderBy:
            sql.append('order by')
            sql.append(orderBy)
        limit = kw.get('limit', None)
        if limit is not None:
            sql.append('limit')
            if isinstance(limit, int):
                sql.append('?')
                args.append(limit)
            elif isinstance(limit, tuple) and len(limit) == 2:
                sql.append('?, ?')
                args.extend(limit)
            else:
                raise ValueError('Invalid limit value: %s' % str(limit))
        rs = db_Select(' '.join(sql), args)

        return [cls(**r) for r in rs]
    @classmethod
    def find(cls, pk):
        ' find object by primary key. '
        rs = db_Select('%s where `%s`=?' % (cls.__select__, cls.__primary_key__), [pk], 1)
        if len(rs) == 0:
            return None
        return cls(**rs[0])


    def save(self):
        args = list(map(self.getValueOrDefault, self.__fields__))
        pk=self.getValueOrDefault(self.__primary_key__)
        args.append(pk)
        print('args:',type(args),str(args))
        rows = db_Instert(self.__insert__, args)
        if rows != 1:
            logging.info('failed to insert record: affected rows: %s' % rows)
            return 0
        return pk

    def update(self):
        args = list(map(self.getValue, self.__fields__))
        args.append(self.getValue(self.__primary_key__))
        rows = db_Update(self.__update__, args)
        if rows != 1:
            logging.warning('failed to update by primary key: affected rows: %s' % rows)

    def remove(self,pk):
        #args = [self.getValue(self.__primary_key__)]
        rows = db_Delete(self.__delete__, [pk])
        if rows != 1:
            logging.warning('failed to remove by primary key: affected rows: %s' % rows)
            return 0
        return pk

2.测试实例文件test_SQLiteORM.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
' a test SQLite ORM util module '
__author__ = 'TianJiang Gui'

from util_SQLiteORM import *

import time, uuid


#---gtj 数值型随机数
def next_id():
    return int(time.time() * 1000)#'%015d' % (

class Userinfo(Model):
    __table__ = 'userinfo'

    id = IntegerField(primary_key=True, default=next_id)
    name = StringField(ddl='varchar(20)')
    age = IntegerField()


def main():
    u = Userinfo(name='Test', age=23)
    uid=u.save()
    if uid>0:
        print('插入新纪录uid=%s成功!'%uid)
        #---gtj 按id查用户信息
        user = Userinfo.find(uid)
        print('新插入记录内容为==>id:', user.id, 'name:', user.name, 'age:', user.age)

    users = Userinfo.findAll()#'name=?',['gtj12']
    for user in users:
        print(type(user),user)
        print('id:',user.id,'name:',user.name,'age:',user.age)
    #---gtj 更新
    u = Userinfo(id=uid, name='Test112', age=112)
    u.update()
    user = Userinfo.find(uid)
    print('id:', user.id, 'name:', user.name, 'age:', user.age)

    #---gtj 按uid删除操作
    did =Userinfo().remove(uid)
    if did > 0:
        print('主键为uid=%s已成功删除!'%did)
    else:
        print('主键为uid=%s不存在,删除失败...'%uid)

if __name__ == '__main__':
    main()

3.运行结果如下:

        1)插入一条新数据并返回uid

python小技巧大应用--实现自己的SQLite3 ORM(全)_第1张图片

        2)按uid查询获得用户信息

python小技巧大应用--实现自己的SQLite3 ORM(全)_第2张图片

python小技巧大应用--实现自己的SQLite3 ORM(全)_第3张图片

         3)查询表中所有记录

python小技巧大应用--实现自己的SQLite3 ORM(全)_第4张图片

python小技巧大应用--实现自己的SQLite3 ORM(全)_第5张图片

         4)更新uid记录

python小技巧大应用--实现自己的SQLite3 ORM(全)_第6张图片

python小技巧大应用--实现自己的SQLite3 ORM(全)_第7张图片

        5)删除uid记录

 python小技巧大应用--实现自己的SQLite3 ORM(全)_第8张图片

总结:代码写得比较粗糙,但已基本能实现应用 

相关建立SQLite表及操作的内容请参见我的其他文章:

python小技巧大应用--测试SQLite是否好用

 python小技巧大应用--自己写sqlite3的CRUD供应用调用

最后,请多关注,点赞我:)

你可能感兴趣的:(python,sqlite,开发语言)