zoukankan      html  css  js  c++  java
  • orm

    1.与之前项目的区别,保存数据使用json文件,项目使用数据库保存数据
    如何将python数据和mysql创建联系
    ①类对应mysql的表,对象对应mysql的记录
    如何创建类的时候自动帮我们创建表,使用到我们的元类
    一切皆对象,对象是类产生的,类也是对象,元类就是产生类的类
    当我们在python 中定义了一个类的时候会立即执行类中代码,触发了其元类的__init__方法
    此方法需要三个参数,类名,类的父类们,类的名称空间
    数据库创建表的sql语句 create table user(id int primary key auto_increment,name char(10));
    现在我们需要知道表名,字段名和字段类型,约束条件
    表名就是类名,字段名可以设置成类的类属性,这样定义类时就类属性会被解析到名称空间,我们就可以在其元类中__init__方法中拿到这些参数
    因为字段还有类型和约束,故将字段设计为Filed类的对象
    
    from orm.ykorm_tool import Mysql
    class Mymeta(type):
        def __init__(self, cls_name, bases, namespace):
            columns = []
            pri_key = None
            for k, v in namespace.items():
                if isinstance(v, Field):
                    fs = "%s %s" % (v.name, v.ctype)
                    if v.pri_key:
                        if pri_key:
                            raise TypeError("主键重复")
                        pri_key = k
                        fs += " primary key auto_increment"
                    if v.default != None:
                        fs += " default %s" % (v.default)
                    columns.append(fs)
            if not pri_key:
                raise TypeError("未设置主键")
            self.pri_key =pri_key
            cs = ",".join(columns)
            sql = "create table %s(%s)" % (cls_name.lower(), cs)
            Mysql.create_table(sql)
    
    class Field:
        def __init__(self, name, ctype, default=None, pri_key=False):
            self.name = name
            self.ctype = ctype
            self.default = default
            self.pri_key = pri_key
    
    class Intfield(Field):
        def __init__(self,name,ctype="int",default=None,pri_key=False):
            super().__init__(name,ctype,default,pri_key)
    
    class Strfield(Field):
        def __init__(self,name,ctype="varchar(200)",default=None,pri_key=False):
            super().__init__(name,ctype,default,pri_key)
    
    class History(metaclass=Mymeta):#当我们写这行时,会自动触发Mymeta.__init__(self,cls_name,bases,namespace)方法
        id = Intfield("id", pri_key=True)
        movie_id= Intfield("movie_id")
        user_id = Intfield("user_id")
        view_time = Strfield("view_time", "timestamp")
    
        def __init__(self, movie_id, user_id):
            self.movie_id = movie_id
            self.user_id = user_id
    

    ②表创建完成后,需要通过数据库帮我们将项目产生的数据保存在对应的表中
    需要使用pymysql模块来使用python操作数据库

    import pymysql
    import time
    from conf.settings import MYSQL_CONF
    #创建连接
    def create_conn(obj):
        conn = pymysql.connect(
            host = MYSQL_CONF["host"],
            user = MYSQL_CONF["user"],
            passwd = MYSQL_CONF["passwd"],
            db = MYSQL_CONF["db"],
            autocommit = MYSQL_CONF["autocommit"],)
        obj.current_conn += 1
        obj.pools.append(conn)
    
    #定义连接类,可以设置最大连接数,保证数据库不会崩
    class Conn:
        pools = []
        current_conn = 0
        def __init__(self,max = 10,retry_time = 0.2):
            self.max = max
            self.retry_time = retry_time
            for i in range(5):
                create_conn(self)
    
        def execute(self,sql,args=None,isselect=False):
            if not self.pools:
                if self.current_conn < self.max:
                    create_conn(self)
                else:
                    time.sleep(self.retry_time)
                    return self.execute(sql,args,isselect)
            conn = self.pools.pop()
            cursor = conn.cursor(pymysql.cursors.DictCursor)
            res = 0
            try:
                res = cursor.execute(sql,args)
            except Exception as e:
                print(e)
            if isselect:
                res = cursor.fetchall()
            self.pools.append(conn)
            return res
    
        def select(self,sql,args=None):
            return self.execute(sql,args,isselect=True)
    

    ③优化了连接问题,需要使用数据库帮我们增删改查数据了
    定义一个Mysql工具类,实现通过主键的增删改查,和通过条件的查询

    from orm.ykorm_conn import Conn
    
    class Mysql:
        __conn = Conn()
    
        @classmethod
        def create_table(cls,sql):
            return cls.__conn.execute(sql)
    
        @classmethod
        def save(cls,obj):
            columns = []
            values = []
            for k,v in obj.__dict__.items():
                columns.append(k)
                values.append(v)
            cs = ",".join(columns)
            vs = ",".join(["%s" for i in values])
            sql = "insert into %s(%s)values(%s)"%(obj.__class__.__name__,cs,vs)
            return cls.__conn.execute(sql,values)
    
    
        @classmethod
        def get(cls,cls_name,id):
            sql = "select * from %s where %s = %s"%(cls_name.__name__,cls_name.pri_key,"%s")
            res = cls.__conn.select(sql,id)
            if not res:return
            obj = object.__new__(cls_name)
            obj.__dict__ = res[0]
            return obj
    
        @classmethod
        def update(cls,obj):
            columns = []
            values = []
            for k,v in obj.__dict__.items():
                fs ="%s = "%k
                fs += "%s"
                columns.append(fs)
                values.append(v)
            cs = ",".join(columns)
            values.append(obj.__dict__[obj.pri_key])
            sql = "update %s set %s where %s = %s"%(obj.__class__.__name__,cs,obj.pri_key,"%s")
            return cls.__conn.execute(sql,values)
    
        @classmethod
        def delete(cls,obj):
            sql = "delete from %s where %s = %s"%(obj.__class__.__name__,obj.pri_key,obj.__dict__[obj.pri_key])
            return cls.__conn.execute(sql)
    
    
        @classmethod
        def get_many(cls,cls_name,conditions=None,limit=None):
            sql = "select * from %s"%cls_name.__name__
            if conditions:
                sql += " where %s"%conditions
            if limit:
                if isinstance(limit,int):
                    sql += "limit %s"%limit
                elif isinstance(limit,tuple):
                    sql += "limit %s,%s"%(limit[0],limit[1])
                else:
                    raise TypeError("limit must be int or tuple")
            res =  cls.__conn.select(sql)
            if not res:return
            objs = []
            for dic in res:
                obj = object.__new__(cls_name)
                obj.__dict__ = dic
                objs.append(obj)
            return objs
    

    以上方法都是类方法,不用产生对象,直接使用MYSQL点方法名,若设置为绑定方法的话,需要将其产生的对象设置为单例模式,因为大家的数据库连接配置都是相同的

  • 相关阅读:
    【队列应用一】随机迷宫|随机起点终点*最短路径算法
    【堆栈应用二】迷宫算法,可直接动态运行
    【堆栈应用一】一个数divided=几个最小质因数的乘积(时间复杂度On)
    MyEclipse2014中Java类右键Run as没有JUnit Test
    C++中break/Continue,exit/return的理解
    windows下用C++修改本机IP地址
    windows下注册表的操作
    详解Java的Spring框架中的注解的用法
    什么是Java Bean
    JS windows对象的top属性
  • 原文地址:https://www.cnblogs.com/robert-zhou/p/10426587.html
Copyright © 2011-2022 走看看