`Scenario 2021-02-16 16:41 采纳率: 0%
浏览 121

大家好ORM框架到cursor.execute(query,args)报错了求大佬帮忙看看要怎么修改

import pymysql

###-------------------属性描述器-------------------###
class Field:   #描述器(类型判断) int  varchar  date  enum  float
    def __init__(self,name,fieldname=None,pk=False,unique=False,default=None,nullable=True,index=False):
        self.name = name
        if fieldname is None:         #字段名为空则将传入name当做字段名
            self.fieldname = name
        else:
            self.fieldname =fieldname
        self.pk = pk
        self.unique = unique
        self.default = default
        self.nullable = nullable
        self.index = index

    def validate(self,value):   #数据校验  分不同类型进行
        raise NotImplementedError

    def __get__(self, instance, owner):  #instance是创建字段student的实例
        if instance is None:             #描述器的get返回的就是字段名--值的字典
            return self
        return instance.__dict__[self.name]

    def __set__(self, instance, value):  #设置字段的值  字段名--值
        self.validate(value)         #set之前先校验数据
        instance.__dict__[self.name] = value   #给对应属性名设置值



    def __str__(self):     #字段实例的本身是哪个  做区分
        return "< {}类型的{}字段 >".format(self.__class__.__name__ , self.name)
    __repr__ = __str__

class IntField(Field):
    def __init__(self,name,fieldname=None,pk=False,unique=False,default=None,nullable=True,auto_increment=False,index=False):
        self.auto_increment = auto_increment  #int仅有
        super().__init__(name,fieldname,pk,unique,default,nullable,index)

    def validate(self,value):   #auto_increment
        if value is None:
            if self.pk:        #主键不可为None
                raise TypeError(u"作为主键的%s 的属性%s 的值%s 异常" % (self.pk,self.name,value))
            if not self.nullable: #如果当前为空  但数据库不允许为空时
                raise TypeError(u"%s required" % self.name)
        else:
            if not isinstance(value,int):  #判断是否为int型数据
                raise TypeError(u"%s should be int" % self.name)



class StringField(Field):   #字符串需要一个长度属性
    def __init__(self,name,length=32,fieldname=None,pk=False,unique=False,default=None,nullable=True,index=False):
        self.length = length
        super().__init__(name,fieldname,pk,unique,default,nullable,index)

    def validate(self,value):
        if value is None:
            if self.pk:        #主键不可为None
                raise (u"作为主键的%s 的属性%s 的值%s 异常" % (self.pk,self.name,value))
            if not self.nullable: #如果当前为空  但数据库不允许为空时
                raise TypeError(u"%s required"% self.name)
        else:
            if not isinstance(value,str):  #判断是否为int型数据
                raise TypeError(u"%s should be str"% self.name)
            if len(value) > self.length:
                raise ValueError(u"字段%s 长度超出范围,value=%s"% (self.name,value) )


###-------------------数据库操作会话 cursor操作的类-------------------###
class Session():    #这种模式会造成线程不安全 有一定风险 但Session应该不跨线程 全局使用
    def __init__(self, conn):#:pymysql.connections.Connection):
        self.conn = conn
        self.cursor = None
        print("初始化完成")


    def execute(self, query,*args):   #SQL执行通用方法  query参数接收SQL语句
        #连接数据库 执行SQL语句      数据库的连接由外部传入,应是全局变量
        if self.cursor is None:   #判断保护 如果没有游标则新建一个
            self.cursor = self.conn.cursor()   #指令参数化 传入的是元组
            print("已建立游标")
        print("已存在游标")
        self.cursor.execute(query,args)



    def __enter__(self):   #with Session实例操作时,单独获取一个游标
        self.cursor = self.conn.cursor()
        return  self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:   #有异常 回滚
            self.conn.rollback()
        else:           #无异常 执行
            self.conn.commit()
        self.cursor.close()


###-------------------元类式反射  定义实体类的模板-------------------###
class ModelMeta(type):   #元类只适合放共性相同的属性和方法
    def __new__(cls, name:str, bases,attrs:dict):       #attrs是 属性-值 的字典
        #解决表名的问题 给了直接用  没给 就用name首字母大写作为表名
        if attrs.get('__tablename__',None)is None:    #获取表名 __tablename__
            attrs['__tablename__'] = name.lower()

        mapping = {}  #映射字典
        primarykey = []  #列表保存主键 主键不止一个!
        for k,v in attrs.items():   #k属性名  v属性所对应的字段类型  保存在mapping字典中
            if isinstance(v,Field):
                mapping[k] = v        #注意:这里在类构建时已经执行
                if v.name is None:
                    v.name = k
                if v.fieldname is None:
                    v.fieldname = v.name
                if v.pk:
                    primarykey.append(v)

        attrs['__mapping__'] = mapping  #未定义时已经把字段属性放到映射字典中保存 作为__mapping__属性
        attrs['primarykey'] = primarykey

        return super().__new__(cls, name, bases,attrs)
"""
session.execute(sql , values)
将sql中的属性名(表名,字段名...)分离出来
values保存对应要添加的值
names保存属性名
"""

class Model(metaclass=ModelMeta): pass  #基类来统一数据库操作

#实体类
class Engine:
    def __init__(self,*args , **kwargs):
        self.conn = pymysql.connect(*args , **kwargs)

    def save(self,instance):
        names = []
        values = []
        for k,v in instance.__mapping__.items():   #注意:当Model子类的实例调用方法时才调用
            if isinstance(v,Field):  #过滤出Field实例化的v
                names.append(k)    #k是属性名     访问v方式:
                values.append(instance.__dict__[k])  #v是属性名对应的Field  访问v方式:__dict__[k]
            #sql = "insert into student(id,name,age)values(%s,%s,%s)"

        sql = "insert into {}({}) values ({})".format(instance.__tablename__ ,",".join(names), ",".join(['%s']*len(names)))   #把values后面的参数拼成列表的形式[%s,%s,%s]
        print(sql)
        print(values)

        session = Session(self.conn)
        with session:
            session.execute(sql, values)


###-------------------数据库连接和操作  实体类-------------------###
class Student(Model):   #操作表student的记录
    __tablename__ = "student"
    id = IntField('id', 'id',True,nullable=False,auto_increment=True)#用描述器来指定属性名称(字段名) 按照int字段来创建 name fieldname pk null ...
    name = StringField('name',length=64,nullable=False)
    age = IntField('age')        #默认age不做pk 默认就为False

    def __init__(self,id,name,age):
        self.tablename = ""
        self.id = id     #调用__set__方法  instance即为当前实例   字典的key为属性名称
        self.name = name
        self.age = age


    # def __str__(self):
    #     return "Student(%s,%s,%s)" % (self.id,self.name,self.age)



if  __name__  == '__main__':
    s = Student(int(1),'tom',int(20))
    engine = Engine(host = "10.0.0.6",port = 3306,user = "root",password='123',db = 'db1',charset='utf8')
    engine.save(s)

  • 写回答

1条回答 默认 最新

  • 久绊A 全栈领域新星创作者 2023-01-23 17:06
    关注
    class ModelMeta(type):   #元类只适合放共性相同的属性和方法
        def __new__(cls, name:str, bases,attrs:dict):       #attrs是 属性-值 的字典
            #解决表名的问题 给了直接用  没给 就用name首字母大写作为表名
            if attrs.get('__tablename__',None)is None:    #获取表名 __tablename__
                attrs['__tablename__'] = name.lower()
    
            mapping = {}  #映射字典
            primarykey = []  #列表保存主键 主键不止一个!
            for k,v in attrs.items():   #k属性名  v属性所对应的字段类型  保存在mapping字典中
                if isinstance(v,Field):
                    mapping[k] = v        #注意:这里在类构建时已经执行
                    if v.name is None:
                        v.name = k
                    if v.fieldname is None:
                        v.fieldname = v.name
                    if v.pk:
                        primarykey.append(v)
    
            attrs['__mapping__'] = mapping  #未定义时已经把字段属性放到映射字典中保存 作为__mapping__属性
            attrs['primarykey'] = primarykey
    
            return super().__new__(cls, name, bases,attrs)
    """
    session.execute(sql , values)
    将sql中的属性名(表名,字段名...
    > 
    
    values保存对应要添加的值
    names保存属性名
    """
    
    class Model(metaclass=ModelMeta): pass  #基类来统一数据库操作
    
    
    评论

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器