day 39
ORM
对象关系映射
- 表 ---> 类
- 字段 ---> 属性
- 记录 ---> 对象
优点:
使用者无需关心具体的SQL命令如何编写。
直接通过调用方法,来执行相对应的SQL命令。
缺点:
1.更高级的封装会导致 “执行效率变低”。
2.会逐渐遗忘SQL原生命令。
# mysql_client.py
import pymysql
class MySQLClient:
def __init__(self):
# 建立连接
self.client = pymysql.connect(
host='localhost',
port=3306,
user='root',
password='123',
database='orm_demo',
charset='utf8',
autocommit=True
)
# 获取游标
self.cursor = self.client.cursor(
pymysql.cursors.DictCursor
)
# 提交查询sql语句并返回结果
def my_select(self, sql, value=None):
print('sql:', sql, '\nvalue:', value)
self.cursor.execute(sql, value)
res = self.cursor.fetchall()
return res
# 提交增加, 修改的sql语句
def my_execute(self, sql, values):
try:
print('<sql>:', sql, '\n<values>:', values)
self.cursor.execute(sql, values)
except Exception as e:
print(e)
# 关闭连接
def close(self):
self.cursor.close()
self.client.close()
# ORM.py
from mysql_client import MySQLClient
# 定义字段类
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
# 定义整数字段类
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(64)', primary_key=False, default=''):
super().__init__(name, column_type, primary_key, default)
# 定义元类
class OrmMetaClass(type):
def __new__(cls, class_name, class_bases, class_dict):
if class_name == 'Models':
return super().__new__(cls, class_name, class_bases, class_dict)
# 没有表名则默认等于类名
table_name = class_dict.get('table_name', class_name)
primary_key = None
# 定义一个空字典, 用来存放字段对象
mappings = {}
for key, value in class_dict.items():
# 筛选字段对象
if isinstance(value, Field):
mappings[key] = value
if value.primary_key:
if primary_key:
raise TypeError('只能有一个主键!')
primary_key = value.name
if not primary_key:
raise TypeError('必须有一个主键!')
# 删除class_dict中和mappings重复的字段属性
for key in mappings.keys():
class_dict.pop(key)
# 将表名添加到class_dict中
class_dict['table_name'] = table_name
# 将主键添加到class_dict中
class_dict['primary_key'] = primary_key
# 将mappings添加到class_dict中
class_dict['mappings'] = mappings
return super().__new__(cls, class_name, class_bases, class_dict)
# 定义Models类
class Models(dict, metaclass=OrmMetaClass):
def __getattr__(self, item):
return self.get(item)
def __setattr__(self, key, value):
self[key] = value
# 查询
@classmethod
def orm_select(cls, **kwargs): # kwargs --> {'id': 1}
mysql = MySQLClient()
# select * from User
if not kwargs:
sql = 'select * from %s' % cls.table_name
res = mysql.my_select(sql)
else:
key = list(kwargs.keys())[0]
value = kwargs.get(key)
sql = 'select * from %s where %s=?' % (cls.table_name, key)
sql = sql.replace('?', '%s')
res = mysql.my_select(sql, value)
mysql.close()
# 返回的是[{}]一个普通的字典(在列表内), 我们把这个字典传入Models类, 让其可以 "对象.属性"
return [cls(**d) for d in res] # d是一个字典
# 增加
def orm_insert(self):
mysql = MySQLClient()
# 存字段名
keys = []
# 存字段值
values = []
# 存 "?"
args = []
for k, v in self.mappings.items():
# 过滤主键, 因为主键是自增的
if not v.primary_key:
# 字段名
keys.append(v.name)
# 字段值, 没有值则使用默认值
values.append(
getattr(self, v.name, v.default)
)
# 有几个字段就存放几个"?"
args.append('?')
sql = 'insert into %s (%s) values (%s)' % (
self.table_name,
','.join(keys),
','.join(args)
)
sql = sql.replace('?', '%s')
print(sql)
print(values)
mysql.my_execute(sql, values)
mysql.close()
# 修改
def orm_update(self):
mysql = MySQLClient()
# 存字段名
keys = []
# 存字段值
values = []
# 主键值
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 %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)
mysql.close()
# 定义用户类
class User(Models):
user_id = IntegerField('user_id', primary_key=True)
user_name = StringField('user_name')
password = StringField('password')
user_obj = User.orm_select(user_id=1)[0] # 查询
print(user_obj) # {'user_id': 1, 'user_name': 'blake', 'password': '123'}
user_obj.user_name = 'bigb' # 修改user_name
user_obj.orm_update() # 将修改提交到数据库
day 39的更多相关文章
- 【转】39个让你受益的HTML5教程
闲话少说,本文作者为大家收集了网上学习HTML5的资源,期望它们可以帮助大家更好地学习HTML5. 好人啊! 不过,作者原来说的40个只有39个,因为第5个和第8个是重复的. 原文在此! 1. 五分钟 ...
- C#开发微信门户及应用(39)--使用微信JSSDK实现签到的功能
随着微信开逐步开放更多JSSDK的接口,我们可以利用自定义网页的方式来调用更多微信的接口,实现我们更加丰富的界面功能和效果,例如我们可以在页面中调用各种手机的硬件来获取信息,如摄像头拍照,GPS信息. ...
- CSharpGL(39)GLSL光照示例:鼠标拖动太阳(光源)观察平行光的漫反射和镜面反射效果
CSharpGL(39)GLSL光照示例:鼠标拖动太阳(光源)观察平行光的漫反射和镜面反射效果 开始 一图抵千言.首先来看鼠标拖动太阳(光源)的情形. 然后是鼠标拖拽旋转模型的情形. 然后我们移动摄像 ...
- 抱歉!15:44-16:39阿里云RDS故障造成全站不能正常访问
非常非常抱歉!2016年3月7日15:44-16:39,由于阿里云RDS(云数据库)故障,造成全站不能正常访问,给您带来了很大很大的麻烦,恳请您的谅解! 故障是在15:44开始出现的,应用日志中出现大 ...
- grep-2.26 sed-4.2.2 awk-4.1.4 wget-1.18 pcregrep-8.39 pcre2grep-10.22 for windows 最新版本静态编译
-------------------------------------------------------------------------------------------- grep (G ...
- 39个让你受益的HTML5教程
1. 五分钟入门HTML5 (Learn HTML5 in 5 Minutes!) By Jennifer Marsman 毫无疑问,HTML5是一个热门话题.如果你需要一个迅速了解HTML基础的速成 ...
- Atitit.自然语言处理--摘要算法---圣经章节旧约39卷概览bible overview v2 qa1.docx
Atitit.自然语言处理--摘要算法---圣经章节旧约39卷概览bible overview v2 qa1.docx 1. 摘要算法的大概流程2 2. 旧约圣经 (39卷)2 2.1. 与古兰经的对 ...
- 颜色代码表#FFFFFF #FF0000 #00FF00 #FF00FF (2015-07-21 10:39)转载
▼标签: 颜色代码表 白色 ffffff 红色 ff0000 黑色 000000 it 分类: hht1 白色 #FFFFFF 2 红色 #FF0000 3 绿色 #00FF00 4 蓝色 # ...
- centos6.5 升级安装pcre 8.39版本
1.查看系统pcre安装情况 rpm -qa pcre 2.卸载系统自带的旧版本 rpm -e --nodeps pcre 3.下载新版安装 地址:ftp://ftp.csx.cam.ac.uk/pu ...
- .Net mvc 后台传单引号错误'
今天调试半天程序 结果出现JS 无法eval() 网上找个半天解决办法无果 最后 是因为后台输出单引号’ 到前台为' 解决办法 给一个隐藏文本框或者标签赋值 再取出来就能显示单引号了
随机推荐
- 洛谷[SHOI2002]滑雪题解
什么破题啊 简直就是浪费我时间! 我每天还被我xf定目标了不知道嘛! 题目 朴素的搜索只能得90分 #include <cstdio> #include <iostream> ...
- 【CSP-S膜你考】 A
A 题面 对于给定的一个正整数n, 判断n是否能分成若干个正整数之和 (可以重复) , 其中每个正整数都能表示成两个质数乘积. 输入格式 第一行一个正整数 q,表示询问组数. 接下来 q 行,每行一个 ...
- Salesforce 开发整理(六) Visualforce分页
分页的实现总体上分真分页和假分页. 所谓真分页指页面上列出来的数据就是实际查询的数据,假分页则是无论页面上一次显示多少条记录,实际上后台已经加载了所有的记录,分页只是为了展示给用户查看.今天分享一个V ...
- python总结八
1.range的使用讲解: 首先呢如果只是一个参数的话,那么就是循环遍历这个参数递增,例如 range(5)>>[1,2,3,4] 如果是两个参数的话,且注意后面的第二个参数要比第一个大, ...
- centos 6.9 安装docker
1.查看系统具体版本 yum install lsb -y lsb_release -a 2.安装yum源 yum -y install http://dl.fedoraproject.org/pub ...
- Linux查看端口使用情况
1.netstat -tunlp,查看已使用的端口 2.netstat -tunlp | grep 8080,查询指定端口使用情况 3.netstat命令无法使用需要安装net-tools yum i ...
- kali 触摸板手势之fusuma
1.执行如下命令进行安装 *fusuma 需要在ruby环境下运行,若计算机不支持ruby,则先执行:apt-get install ruby apt-get update apt-get insta ...
- Java选择结构和循环结构
1.选择结构 ①.ifif(){ } if(){}else{} if(){}else if(){}else if(){}else{} ②.switch switch (表达式) { case 常量 1 ...
- inode是什么?
理解inode,要从文件储存说起. 文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector).每个扇区储存512字节(相当于0.5KB). 操作系统读取硬盘的时候,不会一个 ...
- Sitecore 8.2 防火墙规则的权威指南
如今,使用多层安全保护您的数据不再是奢侈品; 这是不容谈判的.此外,您需要确保Sitecore解决方案保持运行并与集成服务(例如SQL,Mongo,Solr)通信,同时保持相同的安全级别. 让我们假设 ...