ORM.py

'''
ORM: 对象关系映射 ---> 映射到数据库MySQL中的数据表 类名 ---> 表名
对象 ---> 一条记录
对象.属性 ---> 字段 模拟Django的ORM,为了,将数据库的 增、删、改、查,全部封装成
一个个的方式,比如: save, delete, update, select。 优点:
使用者无需 关心具体的SQL命令 如何编写。
直接通过调用方法 来执行相对应的SQL命令。 缺点:
1.更高级的封装导致“执行效率变低”。
2.会逐渐遗忘SQL原生命令。 ''' from mysql_client import MySQLClient # 1.创建字段的类型, 对应数据表中的一个个字段的创建规范
class Field:
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 # Integer
class IntegerField(Field):
def __init__(self, name, column_type='int', primary_key=False, default=0):
super().__init__(name, column_type, primary_key, default) # String
class StringField(Field):
def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None):
super().__init__(name, column_type, primary_key, default) class OrmMetaClass(type):
def __new__(cls, class_name, class_base, class_dict):
# 过滤Models类
if class_name == 'Models':
# models类中,什么都不做,将类原路返回。
return type.__new__(cls, class_name, class_base, class_dict) # 1.一张表必须要有表名
# 假如table_name没有值,则将类名当做表名
table_name = class_dict.get('table_name', class_name) # get--> self.table_name # 2.主键名
primary_key = None # 3.定义一个空字典, 专门用来存放字段对象
mappings = {} # 遍历名称空间中所有的属性
for key, value in class_dict.items():
# print(key, value)
# 除了有字段,还有其他字段以外的属性
# 过滤字段对象以外的内容
if isinstance(value, Field):
mappings[key] = value # 判断字段对象primary_key是否为True
if value.primary_key: # 先判断初识的primary_key是否有值
# 判断主键是否已存在
if primary_key:
raise TypeError('只能有一个主键!') # 若主键不存在,则给primary_key赋值
primary_key = value.name # 节省资源: 因为mappings与原类中名称空间中的属性重复,为了节省内存,剔除重复的属性。
for key in mappings.keys():
class_dict.pop(key) # 判断是否有主键
if not primary_key:
raise TypeError('必须有一个主键') # 给类的名称空间添加表名
class_dict['table_name'] = table_name
# 给类的名称空间添加主键名
class_dict['primary_key'] = primary_key
# 给类的名称空间添加一个mappings字典,字典中拥有所有字段属性
class_dict['mappings'] = mappings
return type.__new__(cls, class_name, class_base, class_dict) class Models(dict, metaclass=OrmMetaClass): # OrmMetaClass(Models, Models_name, base, class_dict)
def __getattr__(self, item):
# print(item, '调用没有的属性时会触发...')
# 将字典的值,返回
return self.get(item) def __setattr__(self, key, value):
# print(key, value)
self[key] = value # 查询方法
# User.orm_select(id=1) ----> user_obj ---》 修改对象的属性值 user_obj.user_name = '李小花' ---》 user_obj.orm_update()
@classmethod
def orm_select(cls, **kwargs):
# kwargs --> {'id': 1}
# 1.调用MySQLClient拿到mysql对象
mysql = MySQLClient() if not kwargs:
# 查询所有 sql: select * from User;
sql = 'select * from %s' % cls.table_name res = mysql.my_select(sql) else:
# dict.keys() ---> 返回的是一个对象,需要转成list类型
key = list(kwargs.keys())[0]
value = kwargs.get(key) # 条件查询 sql: select * from User where id=1;
sql = 'select * from %s where %s=?' % (cls.table_name, key)
sql = sql.replace('?', '%s') # 需要拿到mysql的游标,提交sql语句
# res = mysql.cursor.execute(sql, value)
res = mysql.my_select(sql, value) # d = {'user_id': 1, 'user_name': 'tank', 'pwd': '123'}
# return [cls(**{'user_id': 1, 'user_name': 'tank', 'pwd': '123'}) for d in res] # MySQL ---> [dict, ] --> [{}, {}] ---> [obj, obj] obj.属性取值
return [cls(**d) for d in res] # 插入方法 User(传关键字参数) ---》 user_obj.orm_insert(user_obj)
def orm_insert(self):
mysql = MySQLClient()
# sql: insert into table(f1, f2, f3) values(?, ?, ?); # 存储字段名
keys = [] # 存字段对应的值
values = [] # 存放?号的,有几个字段,就存几个?号
args = [] for k, v in self.mappings.items():
# 过滤掉主键,因为主键是自增的
if not v.primary_key:
# keys.append(k)
# 存表中除了主键以外的字段名
keys.append(v.name) # 存表中除了主键以外的字段值,若值没有,则使用默认值
values.append(
getattr(self, v.name, v.default)
) # 存放?号的,有几个字段,就存几个?号
args.append('?') # sql: insert into table_name(v1, v2, v3) values(?, ?, ?)
sql = 'insert into %s(%s) values(%s)' % (
self.table_name,
','.join(keys),
','.join(args)
) # sql: insert into table_name(v1, v2, v3) values(%s, %s, %s)
sql = sql.replace('?', '%s') mysql.my_execute(sql, values)
# mysql.cursor.execute(sql, values) # 更新方法 update User(传关键字参数) ---》 user_obj.orm_insert(user_obj)
def orm_update(self):
mysql = MySQLClient()
# 字段名
keys = []
# 字段值
values = []
# 主键: id=pk
primary_key = None for k, v in self.mappings.items():
if v.primary_key:
# 只要思想不滑坡,方法总比问题多。
primary_key = v.name + '= %s' % getattr(self, v.name) else:
keys.append(v.name + '=?') values.append(
getattr(self, v.name) # 小贱贱 ---> 大贱贱
) # sql: update table set k1=v1, k2=v2 where id=pk; #
# sql: update table set k1=?, k2=? where id=pk; #
# 注意: tank的更新方法,更新条件固定使用主键。
sql = 'update %s set %s where %s' % (
self.table_name,
','.join(keys),
primary_key
) # sql: update table set k1=%s, k2=%s where id=pk; #
sql = sql.replace('?', '%s') mysql.my_execute(sql, values) # 用户表类
class User(Models): # ---> 表名
# table_name = 'user_info'
# 强调: 最好与字段类型的name属性同名
# user_id自增
user_id = IntegerField(name='user_id', primary_key=True)
user_name = StringField(name='user_name')
pwd = StringField(name='pwd') # 用户表类
class Movie(Models): # ---> 表名
# table_name = 'user_info'
# 强调: 最好与字段类型的name属性同名
user_id = IntegerField(name='user_id', primary_key=True)
user_name = StringField(name='user_name')
pwd = StringField(name='pwd') if __name__ == '__main__':
# ORM:类名 --> 表名 对象 ---> 一条记录 对象.属性 ---> 字段
# user = User(user_name='tank', pwd='123') # 查 orm_select
# 查询所有 sql: select * from User;
# User.select()
# Movie.orm_select()
# 条件查询 sql: select * from User where id=1;
# User.orm_select(id=1)
# res = User.orm_select()[0]
# print(res)
# print(res.user_name) # 增 orm_insert
# User表 ---> 添加字段对应的数据
# user_obj = User(user_name='小贱贱', pwd='123')
# user_obj.orm_insert()
# user_obj = User.orm_select(user_name='小贱贱')[0]
# print(user_obj.user_name) # 改
# user_obj = User.orm_select(user_name='小贱贱')[0]
# print(user_obj.user_name)
# user_obj.user_name = '大贱贱'
# user_obj.orm_update()
user_obj = User.orm_select(user_name='大贱贱')[0]
print(user_obj)

mysql_client.py

import pymysql

class MySQLClient:

    __instance = None

    # 单例模式1
def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls)
return cls.__instance # 单例模式2
# @classmethod
# def singleton(cls):
# if not cls.__instance:
# cls.__instance = cls()
# return cls.__instance # 1.创建连接并获取游标
def __init__(self):
# 连接客户端
self.client = pymysql.connect(
host='127.0.0.1',
port=3306,
user='root',
password='123qwe',
database='orm_demo',
charset='utf8',
autocommit=True
) self.cursor = self.client.cursor(
pymysql.cursors.DictCursor
) # 2.提交查询sql命令
def my_select(self, sql, value=None):
# 提交查询的sql命令
self.cursor.execute(sql, value) # 获取查询以后的结果
res = self.cursor.fetchall()
return res # 3.封装 “提交sql命令,插入或者更新操作”的方法
def my_execute(self, sql, values):
try:
self.cursor.execute(sql, values) except Exception as e:
print(e) # 4.关闭数据库
def close(self):
self.cursor.close()
self.client.close()

封装ORM.py与mysql_client.py代码的更多相关文章

  1. django学习-2.urls.py和view.py的相关知识点

    1.URL函数简单解析 1.1.url() 函数可以接收四个参数,分别是两个必选参数:regex.view,和两个可选参数:kwargs.name. def url(regex, view, kwar ...

  2. 【转】Windows下使用libsvm中的grid.py和easy.py进行参数调优

    libsvm中有进行参数调优的工具grid.py和easy.py可以使用,这些工具可以帮助我们选择更好的参数,减少自己参数选优带来的烦扰. 所需工具:libsvm.gnuplot 本机环境:Windo ...

  3. Python编程核心之makeTextFile.py和readTextFile.py

    引言: 最近大半年都在学习python编程,在双十一的时候购买了<Python编程核心>,看到makeTextFile.py和readTextFile.py两个例子有点错误,所以在这里给修 ...

  4. Libsvm:脚本(subset.py、grid.py、checkdata.py) | MATLAB/OCTAVE interface | Python interface

    1.脚本 This directory includes some useful codes: 1. subset selection tools. (子集抽取工具) subset.py 2. par ...

  5. JAVA之旅(四)——面向对象思想,成员/局部变量,匿名对象,封装 , private,构造方法,构造代码块

    JAVA之旅(四)--面向对象思想,成员/局部变量,匿名对象,封装 , private,构造方法,构造代码块 加油吧,节奏得快点了 1.概述 上篇幅也是讲了这点,这篇幅就着重的讲一下思想和案例 就拿买 ...

  6. django-admin.py和manage.py的用法

    [简介] django-admin.py是Django的一个用于管理任务的命令行工具.本文将描述它的大概用法. 另外,在每一个Django project中都会有一个manage.py.manage. ...

  7. Wifite.py 修正版脚本代码

    Kali2.0系统自带的WiFite脚本代码中有几行错误,以下是修正后的代码: #!/usr/bin/python # -*- coding: utf-8 -*- """ ...

  8. 使用 py.test 对 python 代码进行测试

    其实以前我记得有人对我说过,写代码甚至可以先写完测试之后部署好了再开始写逻辑代码.我觉得有点吃惊和奇怪,这不是扯淡吗? 但是这次在完成了积分支付第一阶段开发之后我意识到,这可能并不是开玩笑,特别是项目 ...

  9. 统计py文件中的代码行

    希望是输入一个合法的文件夹的路径,然后代码自动读取该文件夹下的每个py结尾的文件内的代码行数,最后汇总一个数,但现在只是有思路,却没时间写,这是能读取同级文件下的某个文件, with open('te ...

随机推荐

  1. 强大的BeautifulSoup

    Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库·它能够通过你喜欢的转换器实现惯用的文档导航 安装BeautifulSoup 推荐使用Beautiful Sou ...

  2. GO-REDIS的一些高级用法

    1. 前言 说到Golang的Redis库,用到最多的恐怕是redigo 和 go-redis.其中 redigo 不支持对集群的访问.本文想聊聊go-redis 2个高级用法 2. 开启对Clust ...

  3. 3-2 LInux文件管理

    LInux文件管理 文件系统目录结构 Linux中目录结构是有一定的约定的FHS /bin:存放二进制程序 /boot:启动相关 /dev:设备文件 /etc:配置文件 /home:用户家目录 /li ...

  4. PJzhang:任意密码重置的常规姿势

    猫宁!!! 之前在360补天看过carry_your分享的46分钟短视频“任意用户密码重置的10种姿势”. 在京东SRC安全小课堂第89期,也有一篇他的文章:web漏洞之逻辑漏洞挖掘.内容朴实无华. ...

  5. 【Python开发】python使用urllib2抓取防爬取链接

    前几天刚看完<Linux/Unix设计思想>,真是一本不错的书,推荐想提高自己代码质量的童鞋看一下,里面经常提到要以小为美,一个程序做好一件事,短小精悍,因此我也按照这种思想来写pytho ...

  6. 【DSP开发】【图像处理】Gray与YUV之间的转换关系

    标准的V4L2 API http://v4l.videotechnology.com/dwg/v4l2.pdf 在例程/home/dvevm_1_20/demos/ImageGray中,涉及到图像采集 ...

  7. icon.css

    .icon-blank{ background:url('icons/blank.gif') no-repeat; } .icon-add{ background:url('icons/edit_ad ...

  8. XPath读取xml文件

    1.创建解析工厂 2.创建解析器 3.读xml文件,生成w3c.docment对象树 4.创建XPath对象 5.通过路径查找对象 例子: import javax.xml.parsers.Docum ...

  9. Android开发build出现java.lang.NumberFormatException: For input string: "tle 0x7f0800aa"错误的解决方案

    查看异常栈没有发现项目代码的问题,因为问题是出现在layout文件中. 全局查找tle这个,发现在某个layout文件中title一词被变成ti tle了,结果Android就xjb报错了. 参考

  10. Codeforces 1201D. Treasure Hunting

    传送门 看一眼感觉就是 $dp$,但是似乎状态太多了 考虑推推性质 首先每到一行都要把所有宝藏都走到,那么一定会走到最左边的和最右边的宝藏 注意到一旦走完所有宝藏时肯定是在最左边或者最右边的宝藏位置 ...