博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ORM
阅读量:7052 次
发布时间:2019-06-28

本文共 7570 字,大约阅读时间需要 25 分钟。

orm是一种思想

  对象关系映射思想

  类      》》》      表

  对象     》》》      一条记录

  对象属性   》》》      一条记录下某一字段的值

from my_signleton import MySignleton# 字段类型的属性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 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(255)",primary_key=False,default=""):        super().__init__(name,column_type,primary_key,default)class MyMetaClass(type):    def __new__(cls, class_name, class_bases,class_attrs):        # 我们要拦截是模型表的创建过程,而下面的Model并不需要拦截,所以先做一层判断        if class_name == "Model":            return type.__new__(class_name,class_bases,class_attrs)        # 首先我们要获取的是表名,主键字段名,其他字段名        table_name = class_attrs.get("table_name")        primary_key = None        mappings = {}        for k, v in class_attrs.items():            # 判断出来的都是上面的字段对象            if isinstance(v,Field):                # 判断出主键对象                if v.primary_key:                    # 如果已经存在主键那就报个错                    if primary_key:                        raise TypeError("主键只能由一个")                    primary_key = v                # 剩下的就是其他字段,全都添加到mappings中                mappings[k] = v        # 取出所有字段对象后,class_attrs中就没必要继续存在了,要删掉        for k in mappings.keys():            class_attrs.pop(k)        # 如果一通操作下来还是没有主键,就抛个异常        if not primary_key:            raise TypeError("必须要有一个主键")        # 接下来把我们获得到的几个属性(table_name,primary_key,mappings)添加到名称空间(class_attrs)中        class_attrs["table_name"] = table_name        class_attrs["primary_key"] = primary_key        class_attrs["mappings"] = mappings        # 最后调用type中的new方法        return type.__new__(class_name,class_bases,class_attrs)# 设计一个模型类,可以替代表# (可以点出属性,也可以点设置属性,还可以实例化括号里传可变长生成对象)# 不管传多少参数都能实例化出对象,参考字典类,我们想用这方法只需要继承字典类class Model(dict,metaclass=MyMetaClass):    #字典类打印出来的虽然是一个字典里面有键值对    #但这些键值对并不是他的属性,而我们想直接点出字典里存的东西就只能覆盖字典的__getattr__方法了    #在这里把init方法也重新写一下,方便人们观赏,知道我是继承dict类    def __init__(self,**kwargs):        super().__init__(**kwargs)    # 让字典可以点出属性来    def __getattr__(self,item):        return self.get(item,"没有该键值对")    # 让字典可以通过点进行赋值    def __setattr__(self, key, value):        self[key] = value    # 我可以通过对象的某种特性找出这个对象,所以这个方法是类绑定方法(你不可能产生对象了还去找对象)    # 想要查询,必须传入什么等于什么    @classmethod    def select(cls,**kwargs):        # 生成一个能和数据库对应的对象        ms = MySignleton()        # 不管传入多少判断条件,我们只想取第一条(简单一点),还有一种可能就是不传值,然后查询所有的对象        # 先写不传值的情况        if not kwargs:            # 拼写SQL语句            sql = "select * from %s"%cls.table_name            back_list = ms.select(sql)        else:            column = list(kwargs)[0]            value = kwargs[column]            # 拼接需要的sql语句            # select * from 表名 where 字段=值            sql = "select * from %s where %s = ?"%(cls.table_name,column)            sql.replace("?","%s")            back_list = ms.select(sql,value)        # 要知道这个back_list中都是列表,列表中是字典,而我们想要的结果是列表中套着对象        return [cls(**row) for row in back_list]    # 保存的方法    def save(self):        # sql语句 insert into 表名(字段) values(值)        # 所有的属性都在mappings中,直接遍历mappings就可以        # 需要注意的是,主键都是自增的,所以需要避过主键        # 还有就是有多个属性需要赋值,需要先用列表存一下        column_list = []        values_list = []        seat_list = []        for k, v in self.mappings.items():            if not v.primary_key:                column_list.append(v.name)                values_list.append(getattr(self,v.name))                seat_list.append("?")        # 然后拼写sql语句        sql = "insert into %s(%s) value (%s)"%(self.table_name,','.join(column_list),','.join(seat_list))        sql.replace("?","%s")        # 生成对象        ms = MySignleton()        ms.save(sql,*values_list)    # 如果是要更新的话也不用传入参数,直接遍历出mappings里的值全部修改即可    def update(self):        # sql语句 update 表名 字段=值 where 字段=值        # 这个地方后面的where判断我们就用主键来判断        column_list = []        value_list = []        for k,v in self.mappings.items():            if not v.primary_key:                column_list.append("%s=?"%v.name)                value_list.append(getattr(self,v.name))        sql = "update %s %s where %s=%s"%(self.table_name,','.join(column_list),self.primary_key.name,self.get(self.primary_key.name))        sql.replace("?","%s")        # 生成对象        ms = MySignleton()        ms.save(sql,*value_list)# 每张表必备的表名,主键字段名,还有一些其他字段# 那么怎么让每创建一些类之后,这些属性就会被加到类的属性中呢# 我们想到了拦截类的创建,也就是先自定义元类,拦截模型表的创建,给他填上表需要的几个属性
orm

为了不重复生成操作数据库的对象,我们用两种方式实现

1、单例模式

import pymysql# 我在这需要定义一个类,让orm调用我产生对象# 然后通过我里面的方法把他的和数据库操作对应上# 先连接上数据库并且生成操作数据库对象cursorconn = pymysql.connect(host="localhost", user="root", password="hsjqqq", charset="utf8",                      database="youku",autocommit=True)cursor = conn.cursor(pymysql.cursors.DictCursor)class MySingleton(object):    _instence = None    # 把连接直接写在init方法中,这样只要生成对象就会连接到数据库    # 而不是一导入模块就会连接数据库    def __init__(self):        self.conn = pymysql.connect(            host="localhost", user="root", password="hsjqqq", charset="utf8",            database="youku", autocommit=True        )        self.cursor = self.conn.cursor(pymysql.cursors.DictCursor)    # 传过来sql语句和需要传入的参数(防止sql注入)    def select(self,sql,arg=None):        # execute(self, query, args=None):这个函数中本来就有一个arg默认None        # 所以不管arg有没有传值,我们都可以往execute中取丢        self.cursor.execute(sql,arg)        back_list = self.cursor.fetchall()        return back_list     # 返回查询到的所有的字典列表    def save(self,sql,args):        try:            self.cursor.execute(sql,args)        except Exception as e:            print(e)    # 为了不让每生成一个对象取内存地址开辟一个空间,这里我们用单例模式    @classmethod    def single(cls):        # 先给类一个变量用来存在生成的对象,        # 如果找不到这个对象,那就表名这是第一次产生对象        if not cls._instence:            cls._instence = cls()        # 然后他们每次想生成对象,只需要从我这个变量中拿取即可        return cls._instence
singletion

2、数据库连接池(推荐使用) 

from DBUtils.PooledDB import PooledDBimport pymysqlPOOL = PooledDB(    creator=pymysql,  # 使用链接数据库的模块    maxconnections=6,  # 连接池允许的最大连接数,0和None表示不限制连接数    mincached=2,  # 初始化时,链接池中至少创建的空闲的链接,0表示不创建    maxcached=5,  # 链接池中最多闲置的链接,0和None不限制    maxshared=3,    # 链接池中最多共享的链接数量,0和None表示全部共享。PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。    blocking=True,  # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错    maxusage=None,  # 一个链接最多被重复使用的次数,None表示无限制    setsession=[],  # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]    ping=0,    # ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always    host='127.0.0.1',    port=3306,    user='root',    password='hsjqqq',    database='youku',    charset='utf8',    autocommit='True')class MySingleton(object):    _instence = None    # 把连接直接写在init方法中,这样只要生成对象就会连接到数据库    # 而不是一导入模块就会连接数据库    def __init__(self):        self.conn = POOL.connection()        self.cursor = self.conn.cursor(pymysql.cursors.DictCursor)    # 传过来sql语句和需要传入的参数(防止sql注入)    def select(self,sql,arg=None):        # execute(self, query, args=None):这个函数中本来就有一个arg默认None        # 所以不管arg有没有传值,我们都可以往execute中取丢        self.cursor.execute(sql,arg)        back_list = self.cursor.fetchall()        return back_list     # 返回查询到的所有的字典列表    def save(self,sql,args):        try:            self.cursor.execute(sql,args)        except Exception as e:            print(e)
single_pool

 

转载于:https://www.cnblogs.com/hesujian/p/11086943.html

你可能感兴趣的文章
springMVC的事务不回滚
查看>>
WPF与缓动(三) 指数缓动
查看>>
UPS电源和EPS电源的主要区别
查看>>
虚拟接VMnet1 和VMnet8的区别
查看>>
爱奇艺体育获5亿元战略融资 ,IDG资本、汇盈博润领投
查看>>
三目运算-高级嵌套用法思路教程
查看>>
从编程小白到全栈开发:寻找代码中的问题
查看>>
如何处理地图投影转换
查看>>
区块链技术公司 看区块链数据如何实现安全共享
查看>>
HttpClient-4.5总结(1)
查看>>
Linux_异常_03_Failed to restart iptables.service: Unit not found.
查看>>
LeetCode 169 Majority Element(主要元素)(vector、map)
查看>>
mysql中的几个常用的方法
查看>>
Google 的Android Splash
查看>>
2- 快速上手Linux玩转典型应用- 搭建Linux环境
查看>>
树莓派 之 微信聊天机器人(ItChat)
查看>>
如何学习一门编程语言
查看>>
Java__线程---基础知识全面实战---坦克大战系列为例
查看>>
js时间戳转换日期格式和日期计算
查看>>
真的,移动端尺寸自适应与dpr无关
查看>>