The simple ORM

Orm simple realization

When we use a variety of frameworks, regarding the use of the database in this area, the framework provides us with a very good package, this is the orm

Relational Mapping

Orm nothing more than the underlying relational mapping done

数据库的表(table) --> 类(class)
记录(record,行数据)--> 对象(object)
字段(field)--> 对象的属性(attribute)

ORM design

Field

First of fields, each field has a lot of attributes, then consider that the fields in each table may be different, in order to provide him with better scalability, so here we choose to use class to encapsulate

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

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

class IntegerField(Field):
    def __init__(self,
                 name,
                 column_type='int',
                 primary_key=False,
                 default=None):
        super().__init__(name, column_type, primary_key, default)

table

Table has table and field information, etc.

class Teacher(Models):
    print("teacher")
    table_name='teacher'
    tid = IntegerField(name='tid',primary_key=True)
    tname = StringField(name='tname')

In order to better display, dict data type is more suitable for us, so I finally let him inherit dict, but only through the dictionary value key value, so inconvenient, so we have to rewrite the value of his way to .value

class Models(dict,metaclass=ModelMetaClass):
    print("Models")
    def __init__(self,**kwargs):
        print(f'Models_init')
        super().__init__(self,**kwargs)

    def __getattr__(self, item):
        return self.get(item,"没有该值")

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

To ensure that our own definition of the table when there is no error, we need to add detection step by step, fields, and field better organize

class ModelMetaClass(type):
    print("ModelMetaClass")
    def __new__(cls,class_name,class_base,class_attrs):
        print("ModelMetaClass_new")
        #实例化对象的时候也会执行,我们要把这一次拦截掉
        if class_name == 'Models':
            #为了能让实例化顺利完成,返回一个空对象就行
            return type.__new__(cls,class_name,class_base,class_attrs)
        #获取表名
        table_name = class_attrs.get('table_name',class_name)

        #定义一个存主键的的变量
        primary_key = None

        #定义一个字典存储字段信息
        mapping = {}

        #name='tid',primary_key=True
        #for来找到主键字段
        for k,v in class_attrs.items():
            #判断信息是否是字段
            if isinstance(v,Field):
                mapping[k] = v
                #寻找主键
                if v.primary_key:
                    if primary_key:
                        raise TypeError("主键只有一个")
                    primary_key=v.name

        #将重复的键值对删除,因为已经放入了mapping
        for k in mapping.keys():
            class_attrs.pop(k)
        if not primary_key:
            raise TypeError("表必须要有一个主键")
        class_attrs['table_name']=table_name
        class_attrs['primary_key']=primary_key
        class_attrs['mapping']=mapping
        return type.__new__(cls,class_name,class_base,class_attrs)

Database operations

Database operation is preferably based on the inside, and then use the class method

    #查找
    @classmethod
    def select(cls,**kwargs):
        ms=MySQL()

        #如果没有参数默认是查询全部的
        if not kwargs:
            sql='select * from %s'%cls.table_name
            res=ms.select(sql)
        else:
            k = list(kwargs.keys())[0]
            v = kwargs.get(k)
            sql='select * from %s where %s=?'%(cls.table_name,k)

            #防sql注入
            sql=sql.replace('?','%s')

            res=ms.select(sql,v)
        if res:
            return [cls(**i) for i in res]

    #新增
    def save(self):
        ms=MySQL()

        #存字段名
        fields=[]
        #存值
        values=[]
        args=[]

        for k,v in self.mapping.items():
            #主键自增,不用给他赋值
            if not v.primary_key:
                fields.append(v.name)
                args.append("?")
                values.append(getattr(self,v.name))

            sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args)))

            sql = sql.replace('?','%s')

        ms.execute(sql,values)

    def update(self):
        ms = MySQL()
        fields = []
        valuse = []
        pr = None
        for k,v in self.mapping.items():
            #获取主键值
            if v.primary_key:
                pr = getattr(self,v.name,v.default)
            else:
                fields.append(v.name+'=?')
                valuse.append(getattr(self,v.name,v.default))
            print(fields,valuse)
        sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr)

        sql = sql.replace('?',"%s")

        ms.execute(sql,valuse)

Mysql connection

import pymysql


class MySQL:

    #单例模式
    __instance = None

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self):
        self.mysql = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            database='orm_demo',
            password='root',
            charset='utf8',
            autocommit=True
        )

        #获取游标
        self.cursor = self.mysql.cursor(
            pymysql.cursors.DictCursor
        )

    #查看
    def select(self,sql,args=None):
        #提交sql语句
        self.cursor.execute(sql,args)

        #获取查询的结果
        res = self.cursor.fetchall()
        return res

    #提交
    def execute(self,sql,args):
        #提交语句可能会发生异常
        try:
            self.cursor.execute(sql,args)
        except Exception as e:
            print(e)

    def close(self):
        self.cursor.close()
        self.mysql.close()

Whole code section

MySQL.py

import pymysql


class MySQL:

    #单例模式
    __instance = None

    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance

    def __init__(self):
        self.mysql = pymysql.connect(
            host='127.0.0.1',
            port=3306,
            user='root',
            database='orm_demo',
            password='root',
            charset='utf8',
            autocommit=True
        )

        #获取游标
        self.cursor = self.mysql.cursor(
            pymysql.cursors.DictCursor
        )

    #查看
    def select(self,sql,args=None):
        #提交sql语句
        self.cursor.execute(sql,args)

        #获取查询的结果
        res = self.cursor.fetchall()
        return res

    #提交
    def execute(self,sql,args):
        #提交语句可能会发生异常
        try:
            self.cursor.execute(sql,args)
        except Exception as e:
            print(e)

    def close(self):
        self.cursor.close()
        self.mysql.close()

orm.py

from MySQL import MySQL

# 定义字段类
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

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

class IntegerField(Field):
    def __init__(self,
                 name,
                 column_type='int',
                 primary_key=False,
                 default=None):
        super().__init__(name, column_type, primary_key, default)

class ModelMetaClass(type):
    print("ModelMetaClass")
    def __new__(cls,class_name,class_base,class_attrs):
        print("ModelMetaClass_new")
        #实例化对象的时候也会执行,我们要把这一次拦截掉
        if class_name == 'Models':
            #为了能让实例化顺利完成,返回一个空对象就行
            return type.__new__(cls,class_name,class_base,class_attrs)
        #获取表名
        table_name = class_attrs.get('table_name',class_name)

        #定义一个存主键的的变量
        primary_key = None

        #定义一个字典存储字段信息
        mapping = {}

        #name='tid',primary_key=True
        #for来找到主键字段
        for k,v in class_attrs.items():
            #判断信息是否是字段
            if isinstance(v,Field):
                mapping[k] = v
                #寻找主键
                if v.primary_key:
                    if primary_key:
                        raise TypeError("主键只有一个")
                    primary_key=v.name

        #将重复的键值对删除,因为已经放入了mapping
        for k in mapping.keys():
            class_attrs.pop(k)
        if not primary_key:
            raise TypeError("表必须要有一个主键")
        class_attrs['table_name']=table_name
        class_attrs['primary_key']=primary_key
        class_attrs['mapping']=mapping
        return type.__new__(cls,class_name,class_base,class_attrs)

class Models(dict,metaclass=ModelMetaClass):
    print("Models")
    def __init__(self,**kwargs):
        print(f'Models_init')
        super().__init__(self,**kwargs)

    def __getattr__(self, item):
        return self.get(item,"没有该值")

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

    #查找
    @classmethod
    def select(cls,**kwargs):
        ms=MySQL()

        #如果没有参数默认是查询全部的
        if not kwargs:
            sql='select * from %s'%cls.table_name
            res=ms.select(sql)
        else:
            k = list(kwargs.keys())[0]
            v = kwargs.get(k)
            sql='select * from %s where %s=?'%(cls.table_name,k)

            #防sql注入
            sql=sql.replace('?','%s')

            res=ms.select(sql,v)
        if res:
            return [cls(**i) for i in res]

    #新增
    def save(self):
        ms=MySQL()

        #存字段名
        fields=[]
        #存值
        values=[]
        args=[]

        for k,v in self.mapping.items():
            #主键自增,不用给他赋值
            if not v.primary_key:
                fields.append(v.name)
                args.append("?")
                values.append(getattr(self,v.name))

            sql = "insert into %s(%s) values(%s)"%(self.table_name,",".join(fields),",".join((args)))

            sql = sql.replace('?','%s')

        ms.execute(sql,values)

    def update(self):
        ms = MySQL()
        fields = []
        valuse = []
        pr = None
        for k,v in self.mapping.items():
            #获取主键值
            if v.primary_key:
                pr = getattr(self,v.name,v.default)
            else:
                fields.append(v.name+'=?')
                valuse.append(getattr(self,v.name,v.default))
            print(fields,valuse)
        sql = 'update %s set %s where %s = %s'%(self.table_name,','.join(fields),self.primary_key,pr)

        sql = sql.replace('?',"%s")

        ms.execute(sql,valuse)


class Teacher(Models):
    print("teacher")
    table_name='teacher'
    tid = IntegerField(name='tid',primary_key=True)
    tname = StringField(name='tname')

if __name__ == '__main__':
    # tea=Teacher(tname="haha")
    tea2=Teacher(tname="haha",tid=5)
    # print(Teacher.select(tid=1))
    # Teacher.save(tea)
    print(Teacher.update(tea2))

Guess you like

Origin www.cnblogs.com/zx125/p/11613054.html