ORM

Posted hesujian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ORM相关的知识,希望对你有一定的参考价值。

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
技术图片
import pymysql

# 我在这需要定义一个类,让orm调用我产生对象
# 然后通过我里面的方法把他的和数据库操作对应上
# 先连接上数据库并且生成操作数据库对象cursor
conn = pymysql.connect(host="localhost", user="root", password="hsjqqq", charset="utf8",
                      database="youku",autocommit=True)
cursor = conn.cursor(pymysql.cursors.DictCursor)


class MySignleton(object):
    # 传过来sql语句和需要传入的参数(防止sql注入)
    def select(self,sql,arg=None):
        # execute(self, query, args=None):这个函数中本来就有一个arg默认None
        # 所以不管arg有没有传值,我们都可以往execute中取丢
        cursor.execute(sql,arg)
        back_list = cursor.fetchall()
        return back_list     # 返回查询到的所有的字典列表

    def save(self,sql,args):
        try:
            cursor.execute(sql,args)
        except Exception as e:
            print(e)
mysql_pool

 

以上是关于ORM的主要内容,如果未能解决你的问题,请参考以下文章

第六章 Django框架学习——ORM详解

ORM操作

Django - ORM操作

ORM的概念, ORM到底是什么

Django ORM

ORM常用字段