侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

MySQL数据库设计之利用Python操作Schema方法详解

Python  /  管理员 发布于 7年前   196

弓在箭要射出之前,低声对箭说道,“你的自由是我的”。Schema如箭,弓似Python,选择Python,是Schema最大的自由。而自由应是一个能使自己变得更好的机会。

Schema是什么?

不管我们做什么应用,只要和用户输入打交道,就有一个原则--永远不要相信用户的输入数据。意味着我们要对用户输入进行严格的验证,web开发时一般输入数据都以JSON形式发送到后端API,API要对输入数据做验证。一般我都是加很多判断,各种if,导致代码很丑陋,能不能有一种方式比较优雅的验证用户数据呢?Schema就派上用场了。

㈠ MySQLdb部分

表结构:

mysql> use sakila; mysql> desc actor; +-------------+----------------------+------+-----+-------------------+-----------------------------+ | Field    | Type         | Null | Key | Default      | Extra| +-------------+----------------------+------+-----+-------------------+-----------------------------+ | actor_id  | smallint(5) unsigned | NO  | PRI | NULL       | auto_increment       | | first_name | varchar(45)     | NO  |   | NULL       |   | | last_name  | varchar(45)     | NO  | MUL | NULL       |   | | last_update | timestamp      | NO  |   | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | +-------------+----------------------+------+-----+-------------------+-----------------------------+ 4 rows in set (0.00 sec) 

数据库连接模块:

[root@DataHacker ~]# cat dbapi.py #!/usr/bin/env ipython #coding = utf-8 #Author: [email protected] #Time: 2014-1-29  import MySQLdb as dbapi  USER = 'root' PASSWD = 'oracle' HOST = '127.0.0.1' DB = 'sakila'  conn = dbapi.connect(user=USER,passwd=PASSWD,host=HOST,db=DB) 

1 打印列的元数据

[root@DataHacker ~]# cat QueryColumnMetaData.py #!/usr/bin/env ipython  from dbapi import *  cur = conn.cursor() statement = """select * from actor limit 1""" cur.execute(statement)  print "output column metadata....." print for record in cur.description:   print record  cur.close() conn.close() 

1.)调用execute()之后,cursor应当设置其description属性
2.)是个tuple,共7列:列名、类型、显示大小、内部大小、精度、范围以及一个是否接受null值的标记

[root@DataHacker ~]# chmod +x QueryColumnMetaData.py [root@DataHacker ~]# ./QueryColumnMetaData.py output column metadata.....  ('actor_id', 2, 1, 5, 5, 0, 0) ('first_name', 253, 8, 45, 45, 0, 0) ('last_name', 253, 7, 45, 45, 0, 0) ('last_update', 7, 19, 19, 19, 0, 0) 

2 通过列名访问列值

默认情况下,获取方法从数据库作为"行"返回的值是元组

In [1]: from dbapi import * In [2]: cur = conn.cursor() In [3]: v_sql = "select actor_id,last_name from actor limit 2" In [4]: cur.execute(v_sql) Out[4]: 2L In [5]: results = cur.fetchone() In [6]: print results[0] 58 In [7]: print results[1] AKROYD 

我们能够借助cursorclass属性来作为字典返回

In [2]: import MySQLdb.cursors In [3]: import MySQLdb In [4]: conn = MySQLdb.connect(user='root',passwd='oracle',host='127.0.0.1',db='sakila',cursorclass=MySQLdb.cursors.DictCursor) In [5]: cur = conn.cursor() In [6]: v_sql = "select actor_id,last_name from actor limit 2" In [7]: cur.execute(v_sql) Out[7]: 2L In [8]: results = cur.fetchone() In [9]: print results['actor_id'] 58 In [10]: print results['last_name'] AKROYD 

㈡ SQLAlchemy--SQL炼金术师

虽然SQL有国际标准,但遗憾的是,各个数据库厂商对这些标准的解读都不一样,并且都在标准的基础上实现了各自的私有语法。为了隐藏不同SQL“方言”之间到区别,人们开发了诸如SQLAlchemy之类的工具

SQLAlchemy连接模块:

[root@DataHacker Desktop]# cat sa.py import sqlalchemy as sa engine = sa.create_engine('mysql://root:[email protected]/testdb',pool_recycle=3600) metadata = sa.MetaData() 

example 1:表定义

In [3]: t = Table('t',metadata,    ...:        Column('id',Integer),    ...:        Column('name',VARCHAR(20)),    ...:        mysql_engine='InnoDB',    ...:        mysql_charset='utf8'    ...:       )  In [4]: t.create(bind=engine) 

example 2:表删除

有2种方式,其一: In [5]: t.drop(bind=engine,checkfirst=True)  另一种是: In [5]: metadata.drop_all(bind=engine,checkfirst=True),其中可以借助tables属性指定要删除的对象 

example 3: 5种约束

3 .1 primary key 下面2种方式都可以,一个是列级,一个是表级 In [7]: t_pk_col = Table('t_pk_col',metadata,Column('id',Integer,primary_key=True),Column('name',VARCHAR(20))) In [8]: t_pk_col.create(bind=engine) In [9]: t_pk_tb = Table('t_pk_01',metadata,Column('id',Integer),Column('name',VARCHAR(20)),PrimaryKeyConstraint('id','name',name='prikey')) In [10]: t_pk_tb.create(bind=engine) 3.2 Foreign Key In [13]: t_fk = Table('t_fk',metadata,Column('id',Integer,ForeignKey('t_pk.id'))) In [14]: t_fk.create(bind=engine) In [15]: t_fk_tb = Table('t_fk_tb',metadata,Column('col1',Integer),Column('col2',VARCHAR(10)),ForeignKeyConstraint(['col1','col2'],['t_pk.id','t_pk.name'])) In [16]: t_fk_tb.create(bind=engine) 3.3 unique In [17]: t_uni = Table('t_uni',metadata,Column('id',Integer,unique=True)) In [18]: t_uni.create(bind=engine) In [19]: t_uni_tb = Table('t_uni_tb',metadata,Column('col1',Integer),Column('col2',VARCHAR(10)),UniqueConstraint('col1','col2')) In [20]: t_uni_tb.create(bind=engine) 3.4 check    虽然能成功,但MySQL目前尚未支持check约束。这里就不举例了。 3.5 not null In [21]: t_null = Table('t_null',metadata,Column('id',Integer,nullable=False)) In [22]: t_null.create(bind=engine) 

4 默认值

分2类:悲观(值由DB Server提供)和乐观(值由SQLAlshemy提供),其中乐观又可分:insert和update

4.1 例子:insert In [23]: t_def_inser = Table('t_def_inser',metadata,Column('id',Integer),Column('name',VARCHAR(10),server_default='cc')) In [24]: t_def_inser.create(bind=engine) 3.2 例子:update In [25]: t_def_upda = Table('t_def_upda',metadata,Column('id',Integer),Column('name',VARCHAR(10),server_onupdate='DataHacker')) In [26]: t_def_upda.create(bind=engine) 3.3 例子:Passive  In [27]: t_def_pass = Table('t_def_pass',metadata,Column('id',Integer),Column('name',VARCHAR(10),DefaultClause('cc'))) In [28]: t_def_pass.create(bind=engine) 

㈢ 隐藏Schema

数据的安全是否暴露在完全可信任的对象面前,这是任何有安全意识的DBA都不会去冒的风险。比较好的方式是尽可能隐藏Schema结构并验证用户输入的数据完整性,这在一定程度上虽然增加了运维成本,但安全无小事。

这里借助开发一个命令行工具来阐述该问题

需求:隐藏表结构,实现动态查询,并将结果模拟mysql \G输出

版本: [root@DataHacker ~]# ./sesc.py --version 1.0 查看帮助: [root@DataHacker ~]# ./sesc.py -h Usage: sesc.py [options] <arg1> <arg2> [<arg3>...] Options:  --version       show program's version number and exit  -h, --help      show this help message and exit  -q TERM        assign where predicate  -c COL, --column=COL assign query column  -t TABLE       assign query table  -f, --format     -f must match up -o  -o OUTFILE      assign output file 我们要的效果: [root@DataHacker ~]# ./sesc.py -t actor -c last_name -q s% -f -o output.txt [root@DataHacker ~]# cat output.txt ************ 1 row ******************* actor_id: 180 first_name: JEFF last_name: SILVERSTONE last_update: 2006-02-15 04:34:33 ************ 2 row ******************* actor_id: 195 first_name: JAYNE last_name: SILVERSTONE last_update: 2006-02-15 04:34:33 ......<此处省略大部分输出>...... 

请看代码

#!/usr/bin/env pythonimport optparsefrom dbapi import *#构造OptionParser实例,配置期望的选项parser = optparse.OptionParser(usage="%prog [options] <arg1> <arg2> [<arg3>...]",version='1.0',)#定义命令行选项,用add_option一次增加一个parser.add_option("-q",action="store",type="string",dest="term",help="assign where predicate")parser.add_option("-c","--column",action="store",type="string",dest="col",help="assign query column")parser.add_option("-t",action="store",type="string",dest="table",help="assign query table")parser.add_option("-f","--format",action="store_true",dest="format",help="-f must match up -o")parser.add_option("-o",action="store",type="string",dest="outfile",help="assign output file")#解析命令行options,args = parser.parse_args()#把上述dest值赋给我们自定义的变量table = options.tablecolumn = options.colterm = options.termformat = options.format#实现动态读查询statement = "select * from %s where %s like '%s'"%(table,column,term)cur = conn.cursor()cur.execute(statement)results = cur.fetchall()#模拟 \G 输出形式if format is True: columns_query = "describe %s"%(table) cur.execute(columns_query) heards = cur.fetchall() column_list = [] for record in heards:  column_list.append(record[0]) output = "" count = 1 for record in results:  output = output + "************ %s row ************\n\n"%(count)  for field_no in xrange(0, len(column_list)):   output = output + column_list[field_no]+ ": " + str(record[field_no]) + "\n"  output = output + "\n"  count = count + 1else: output = [] for record in xrange(0,len(results)):  output.append(results[record]) output = ''.join(output)#把输出结果定向到指定文件if options.outfile: outfile = options.outfile with open(outfile,'w') as out:  out.write(output)else: print output#关闭游标与连接conn.close()cur.close()

总结

以上就是本文关于MySQL数据库设计之利用Python操作Schema方法详解的全部内容,希望对大家有所帮助。欢迎参阅:Python定时器实例代码、Python生成数字图片代码分享等,有什么问题可以随时留言,小编会及时回复大家的,欢迎留言交流讨论。


  • 上一条:
    Linux安装Python虚拟环境virtualenv的方法
    下一条:
    最详细的Python库总结
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客