orm之sqlarchemy 底层实现原理

Posted qingqinxu

tags:

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

ORM 【即Object Relational Mapping,对象关系映射】sqlarchemy底层是如何实现的?
当我们需要对数据库进行操作时,是否可以依如下方式操作数据库-- 不要写sql语句,我要写python代码

创建表   --------   创建类

行数据   --------   对象

操作行数据  ----  操作对象   

问题:1.首先需要一个类,实例一个对象就是一行数据。

     2. 是否可以找到一种用点的方式的获取数据的数据类型,因为给对象添加属性:【obj.name=‘egon‘】 ,访问对象属性【obj.name】

        所学数据类型中貌似字典比较可以,先来实例化一个字典对象

    dic = dict(name=‘egon‘,age=18)
   print(dic) #‘name‘: ‘egon‘, ‘age‘: 18
            

   3.  字典只能加中括号 dic[ ‘ name ‘] 取值,赋值。是否可以重写一个dict 类,改变一下对象dic取值的方式?

     可通过重写dict类中的内置方法__ setattr__、 __getattr__ 使字典对象可以像普通对象一样用给自己添加属性【obj.name=‘ jerry ‘】、访问属性【obj.name】。

    class A(dict):

       def __setattr__(self, key, value):
      #修改、新增时触发
      print(‘这是settattr key:%a, value:%s‘%(key,value))
       self[key] = value

      def __getattr__(self, item):
       print(‘getattr item:%s‘% item)
      #取值时触发
       try:
       return self[item]
       except TypeError:
         raise (‘没有该属性 ‘)
    obj = A()

    # obj[‘name‘]=‘egon‘ 原来就有的添加属性的方式
    # obj[‘password‘] =123
    #

    obj.name = ‘jerry‘ # 新增、修改时会触发__setattr__ 的执行
    print(obj.name) # jerry 对象取值时触发__getattr__ 的执行

    4. 对象添加、获取数据用点方法问题解决了之后,需要对类的实例进行限制:

      a. 必须要有表名

      b. 必须要有对主键的描述
      c. 给所有实例化的类一个表结构信息

    5. 这里就需要一个元类来限制类中必须有上面这些内容   == 每一个表必须要有的内容也就有了

class ModlesMetaclas(type):
def __new__(cls, name, bases, attrs):
if name == ‘Modles‘:
return type.__new__(cls, name, bases, attrs) # 当类名为基类时就不要拦截
table_name = attrs.get(‘table_name‘, None)
if not table_name:
table_name = name
primary_key = None
mappings = dict()
for k, v in attrs.items():
if isinstance(v, Filed):
mappings[k] = v
if v.primary_key:
if primary_key:
raise TypeError(‘主键重复:%s‘ % k)
primary_key = k
for k in mappings.keys():
attrs.pop(k)
# if not primary_key:
# raise TypeError(‘没有主键‘)
attrs[‘table‘] = table_name
attrs[‘primary_key‘] = primary_key
attrs[‘mappings‘] = mappings
return type.__new__(cls, name, bases, attrs)


class Modles(dict, metaclass=ModlesMetaclas):
def __init__(self, **kwargs): # 实例对象时必须是关键字传参 给User实例对象时用的
super().__init__(**kwargs)

def __setattr__(self, key, value): # 字典中有这个key就覆盖新的值,没有就装入到self这个字典中
self[key] = value

def __getattr__(self, item):
try:
return self[item] # dic.name时【item类比是name】返回字典的value值
except TypeError:
raise (‘没有该属性 ‘)
  
@classmethod
def select_one(cls, **kwargs):
# 只查一条
key = list(kwargs.keys())[0]
value = kwargs[key]
# select * from user where id=%s
sql = ‘select * from %s where %s=?‘ % (cls.table_name, key)
#
sql = sql.replace(‘?‘, ‘%s‘)
ms = mysql_singleton.Mysql().singleton()
re = ms.select(sql, value)
if re:
# attrs=‘name‘:‘123‘,‘password‘:123
# u=User(**attrs)
# 相当于 User(name=‘123‘,password=123)
u = cls(**re[0])
return u
else:
return

@classmethod
def select_many(cls, **kwargs):
ms = Mysql_singleton.Mysql().singleton()
if kwargs:
key = list(kwargs.keys())[0]
value = kwargs[key]
sql = ‘select * from %s where %s=?‘ % (cls.table_name, key)
#
sql = sql.replace(‘?‘, ‘%s‘)

re = ms.select(sql, value)
else:
sql = ‘select * from %s‘ % (cls.table_name)
re = ms.select(sql)

if re:
lis_obj = [cls(**r) for r in re]
return lis_obj
else:
return

def update(self):
ms = Mysql_singleton.Mysql().singleton()
# update user set name=?,password=? where id=1

filed = []
pr = None
args = []
for k, v in self.mappings.items():

if v.primary_key:
pr = getattr(self, v.name, None)
else:
filed.append(v.name + ‘=?‘)
args.append(getattr(self, v.name, v.default))

sql = ‘update %s set %s where %s =%s‘ % (self.table_name, ‘,‘.join(filed), self.primary_key, pr)
# ‘update user set name=?,password =? where id =1‘
sql = sql.replace(‘?‘, ‘%s‘)
ms.execute(sql, args)

def save(self):
ms = Mysql_singleton.Mysql().singleton()
# insert into user (name,passwword) values (?,?)
filed = []
values = []
args = []
for k, v in self.mappings.items():
if not v.primary_key:
filed.append(v.name)
values.append(‘?‘)
args.append(getattr(self, v.name, v.default))
sql = ‘insert into %s (%s) VALUES (%s)‘ % (self.table_name, ‘,‘.join(filed), ‘,‘.join(values))
sql = sql.replace(‘?‘, ‘%s‘)
ms.execute(sql, args)



class User(Modles):

table_name=‘user‘
id=IntegerFileld(‘id‘,primary_key=True,default=0)
name=StringFiled(‘name‘)
password=StringFiled(‘password‘)

class Notic(Modles):
table_name=‘notice‘
id = IntegerFileld(‘id‘,primary_key=True)
name=StringFiled(‘name‘)
content=StringFiled(‘content‘)
user_id=IntegerFileld(‘user_id‘)

   6. 另外实例化的User类【表】中的每一个属性【列】如id、name等都必须要有类型如int类型、char类型,那就来定义一些类吧:

class Filed:
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 StringFiled(Filed):
def __init__(self, name=None, column_type=‘varchar(200)‘, primary_key=False, default=None):
super().__init__(name, column_type, primary_key, default)


class IntegerFileld(Filed):
def __init__(self, name=None, column_type=‘int‘, primary_key=False, default=None):
super().__init__(name, column_type, primary_key, default)

 

以上是关于orm之sqlarchemy 底层实现原理的主要内容,如果未能解决你的问题,请参考以下文章

很多小伙伴不太了解ORM框架的底层原理,这不,冰河带你10分钟手撸一个极简版ORM框架(赶快收藏吧)

Git系列之底层原理篇

跨域详解之jsonp,底层的实现原理

SQLarchemy 实现外键及其四种约束讲解

JUC回顾之-CyclicBarrier底层实现和原理

理解数据库连接池底层原理之手写实现