登录  /  注册

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

小云云
发布: 2017-12-08 09:52:50
原创
1496人浏览过

schema是什么?

不管我们做什么应用,只要和用户输入打交道,就有一个原则--永远不要相信用户的输入数据。意味着我们要对用户输入进行严格的验证,web开发时一般输入数据都以JSON形式发送到后端API,API要对输入数据做验证。一般我都是加很多判断,各种if,导致代码很丑陋,能不能有一种方式比较优雅的验证用户数据呢?Schema就派上用场了。本文主要介绍了MySQL数据库设计之利用Python操作Schema方法详解,还是比较不错的,这里分享给大家,供需要的朋友参考。

㈠ MySQLdb部分

表结构:

<a style='color:#f60; text-decoration:underline;' href="https://www.php.cn/zt/15713.html" target="_blank">mysql</a>> 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 i<a style='color:#f60; text-decoration:underline;' href="https://www.php.cn/zt/15730.html" target="_blank">python</a> 
#coding = utf-8 
#Author: linwaterbin@gmail.com 
#Time: 2014-1-29 
 
import MySQLdb as dbapi 
 
USER = &#39;root&#39; 
PASSWD = &#39;oracle&#39; 
HOST = &#39;127.0.0.1&#39; 
DB = &#39;sakila&#39; 
 
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..... 
 
(&#39;actor_id&#39;, 2, 1, 5, 5, 0, 0) 
(&#39;first_name&#39;, 253, 8, 45, 45, 0, 0) 
(&#39;last_name&#39;, 253, 7, 45, 45, 0, 0) 
(&#39;last_update&#39;, 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=&#39;root&#39;,passwd=&#39;oracle&#39;,host=&#39;127.0.0.1&#39;,db=&#39;sakila&#39;,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[&#39;actor_id&#39;] 
58 
In [10]: print results[&#39;last_name&#39;] 
AKROYD
登录后复制

㈡ SQLAlchemy--SQL炼金术师

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

SQLAlchemy连接模块:

[root@DataHacker Desktop]# cat sa.py 
import sqlalchemy as sa 
engine = sa.create_engine(&#39;mysql://root:oracle@127.0.0.1/testdb&#39;,pool_recycle=3600) 
metadata = sa.MetaData()
登录后复制

example 1:表定义

In [3]: t = Table(&#39;t&#39;,metadata, 
   ...:        Column(&#39;id&#39;,Integer), 
   ...:        Column(&#39;name&#39;,VARCHAR(20)), 
   ...:        mysql_engine=&#39;InnoDB&#39;, 
   ...:        mysql_charset=&#39;utf8&#39; 
   ...:       ) 
 
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(&#39;t_pk_col&#39;,metadata,Column(&#39;id&#39;,Integer,primary_key=True),Column(&#39;name&#39;,VARCHAR(20))) 
In [8]: t_pk_col.create(bind=engine) 
In [9]: t_pk_tb = Table(&#39;t_pk_01&#39;,metadata,Column(&#39;id&#39;,Integer),Column(&#39;name&#39;,VARCHAR(20)),PrimaryKeyConstraint(&#39;id&#39;,&#39;name&#39;,name=&#39;prikey&#39;)) 
In [10]: t_pk_tb.create(bind=engine) 
3.2 Foreign Key 
In [13]: t_fk = Table(&#39;t_fk&#39;,metadata,Column(&#39;id&#39;,Integer,ForeignKey(&#39;t_pk.id&#39;))) 
In [14]: t_fk.create(bind=engine) 
In [15]: t_fk_tb = Table(&#39;t_fk_tb&#39;,metadata,Column(&#39;col1&#39;,Integer),Column(&#39;col2&#39;,VARCHAR(10)),ForeignKeyConstraint([&#39;col1&#39;,&#39;col2&#39;],[&#39;t_pk.id&#39;,&#39;t_pk.name&#39;])) 
In [16]: t_fk_tb.create(bind=engine) 
3.3 unique 
In [17]: t_uni = Table(&#39;t_uni&#39;,metadata,Column(&#39;id&#39;,Integer,unique=True)) 
In [18]: t_uni.create(bind=engine) 
In [19]: t_uni_tb = Table(&#39;t_uni_tb&#39;,metadata,Column(&#39;col1&#39;,Integer),Column(&#39;col2&#39;,VARCHAR(10)),UniqueConstraint(&#39;col1&#39;,&#39;col2&#39;)) 
In [20]: t_uni_tb.create(bind=engine) 
3.4 check 
   虽然能成功,但MySQL目前尚未支持check约束。这里就不举例了。 
3.5 not null 
In [21]: t_null = Table(&#39;t_null&#39;,metadata,Column(&#39;id&#39;,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(&#39;t_def_inser&#39;,metadata,Column(&#39;id&#39;,Integer),Column(&#39;name&#39;,VARCHAR(10),server_default=&#39;cc&#39;)) 
In [24]: t_def_inser.create(bind=engine) 
3.2 例子:update 
In [25]: t_def_upda = Table(&#39;t_def_upda&#39;,metadata,Column(&#39;id&#39;,Integer),Column(&#39;name&#39;,VARCHAR(10),server_onupdate=&#39;DataHacker&#39;)) 
In [26]: t_def_upda.create(bind=engine) 
3.3 例子:Passive  
In [27]: t_def_pass = Table(&#39;t_def_pass&#39;,metadata,Column(&#39;id&#39;,Integer),Column(&#39;name&#39;,VARCHAR(10),DefaultClause(&#39;cc&#39;))) 
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&#39;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 python
import optparse
from dbapi import *

#构造OptionParser实例,配置期望的选项
parser = optparse.OptionParser(usage="%prog [options] <arg1> <arg2> [<arg3>...]",version=&#39;1.0&#39;,)
#定义命令行选项,用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.table
column = options.col
term = options.term
format = options.format
#实现动态读查询
statement = "select * from %s where %s like &#39;%s&#39;"%(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 + 1
else:
 output = []
 for record in xrange(0,len(results)):
  output.append(results[record])
 output = &#39;&#39;.join(output)
#把输出结果定向到指定文件
if options.outfile:
 outfile = options.outfile
 with open(outfile,&#39;w&#39;) as out:
  out.write(output)
else:
 print output
#关闭游标与连接
conn.close()
cur.close()
登录后复制

相关推荐:

关于数据库中table与schema的区别详解

MySQL中关于information_schema的详细介绍

MySQL分布式集群之MyCAT(二)schema代码详解

以上就是MySQL数据库利用Python操作Schema方法详解的详细内容,更多请关注php中文网其它相关文章!

智能AI问答
PHP中文网智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。
相关标签:
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
最新问题
关于CSS思维导图的课件在哪? 课件
凡人来自于2024-04-16 10:10:18
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2024 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号