导出数据库表文档到word。
使用pyhton的python-docx框架实现导出数据库表结构为word格式。
前言:
本人自学python,语法不精通,参考人员注意甄别。
问题:
由于近期甲方项目需要验收,需要完成数据库er,和数据库文档,由于没有搜索到需要的插件/方案(网上只有半自动化,每次只能自己手动操作一个个导出,效率太低)故自己尝试手写了一个。
实现样式如下:
下面是单个的样式,代码内部会遍历所有的表,有多少个表就会往word内写入多少个表格
后面只需要自己配置头部的公司信息,和其他自己所需要的文件即可,最后手动生成目录
上python代码:
部分代码是写死的,例如(上图)表左,表头
# -*- coding:utf-8 -*-
# 数据库验收文档导出er关系表信息
import sys
import os
from docx.opc.oxml import parse_xml
from docx.oxml.ns import nsdecls
from docx.shared import RGBColor, Cm, Pt
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
import pymysql
from pymysql.cursors import DictCursor
from docx import Document
# mysql超时时间设置
connect_timeout = 10
# 创建mysql链接
def connMysql():
return pymysql.connect(host="url地址", port=数据库端口, user="数据库用户名",password="数据库密码", db="库名称", charset="utf8")
# 获取数据库所有表名称
def getAllDBName():
conn = connMysql()
# 建立游标,制定游标类型,返回字典
cur = conn.cursor(DictCursor);
# 执行sql语句
cur.execute("select table_name,table_comment from information_schema.tables where table_schema='数据库名称'") # param
# 返回查询所有
res = cur.fetchall()
# 关闭游标
cur.close()
# 关闭连接
conn.close()
# print("当前库下所有表的名称")
# for i in res:
# print(i["table_name"])
return res
# 获取当前表描述
def getAllDBDDL(dbName, dbComment):
conn = connMysql()
# 建立游标,制定游标类型,返回字典
cur = conn.cursor(DictCursor);
# 执行sql语句
cur.execute(
"SELECT COLUMN_NAME 列名, COLUMN_TYPE 数据类型,DATA_TYPE 字段类型,IS_NULLABLE 是否为空,COLUMN_DEFAULT 默认值,COLUMN_COMMENT 备注 FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = 'zhongtie' AND table_name = '%s'" % (
dbName)) # param
# 返回查询所有
res = cur.fetchall()
# 关闭游标
cur.close()
# 关闭连接
conn.close()
print(dbName + "[%s]" % (dbComment))
for i in res:
print(i)
return res
shading_list = locals()
def leftComment(doc):
# 获取第一行第二列单元格
cell = doc.cell(0, 0)
# 设置单元格文本
cell.text = "表名"
cell = doc.cell(1, 0)
# 设置单元格文本
cell.text = "库名"
cell = doc.cell(2, 0)
# 设置表格背景色
for rgbsIndex in range(0, 3):
shading_list['shading_elm_' + str(i)] = parse_xml(
r'<w:shd {} w:fill="{bgColor}"/>'.format(nsdecls('w'), bgColor="#C0C0C0"))
doc.rows[rgbsIndex].cells[0]._tc.get_or_add_tcPr().append(shading_list['shading_elm_' + str(i)])
# 设置单元格文本
cell.text = "内容描述"
def rightComment(doc, dbname):
cell = doc.cell(0, 1)
# 设置单元格文本
cell.text = dbname
cell = doc.cell(1, 1)
# 设置单元格文本
cell.text = "zhongtie"
cell = doc.cell(2, 1)
# 设置单元格文本
cell.text = "用于存储组数据。"
def topComment(doc):
cell = doc.cell(0, 0)
# 设置单元格文本
cell.text = "序号"
cell = doc.cell(0, 1)
# 设置单元格文本
cell.text = "列名"
cell = doc.cell(0, 2)
# 设置单元格文本
cell.text = "类型"
cell = doc.cell(0, 3)
# 设置单元格文本
cell.text = "长度"
cell = doc.cell(0, 4)
# 设置单元格文本
cell.text = "为空"
cell = doc.cell(0, 5)
# 设置单元格文本
cell.text = "说明"
cell = doc.cell(0, 6)
# 设置单元格文本
cell.text = "主键"
# 设置表格背景色
for rgbsIndex in range(0, 7):
shading_list['shading_elm_' + str(i)] = parse_xml(
r'<w:shd {} w:fill="{bgColor}"/>'.format(nsdecls('w'), bgColor="#C0C0C0"))
doc.rows[0].cells[rgbsIndex]._tc.get_or_add_tcPr().append(shading_list['shading_elm_' + str(i)])
# 添加一级标题
# document.add_heading('我是一级标题')
#
# decument.add_heading('我是二级标题', level=2)
#
# decument.add_heading('我是段落标题', level=0)
if __name__ == "__main__":
# 如果需要在完成的数据内插入多个标题则这里就往后移动 例如插入三个下面就从4下标开始,方便后期完成目录的生成
levelLine = 2
# 获取所有的数据库表名
res = getAllDBName()
# word文档
document = Document()
# 这里遍历获取到的所有的表名 和 注释 信息
for i in res:
# 组装名称 例 : tableName[注释]
tableAndComment = "{0}[{1}]".format(i['table_name'], i['table_comment'])
# 组装名称 例 : 1.tableName[注释] 方便插入标题使用
str1 = "{0}.{1}".format(levelLine, tableAndComment)
# 这里写入一级标题
T1_1 = document.add_heading('', level=1)
# 获取run 来操作其他参数
run_T1_1 = T1_1.add_run(str1)
# 设置字体格式 一级标题不适合设置字体样式 会导致难看? ps:中文字体设置样式需要修改其他参数
# run_T1_1.font.name = '宋体'
# 设置标题颜色
# 通过run修改 字体颜色
run_T1_1.font.color.rgb = RGBColor(0, 0, 0)
run_T1_1.font.bold = True
# 获取表的DDL描述信息
dbAll = getAllDBDDL(i['table_name'], i['table_comment'])
# 创建表描述表格 3行 2列 实线
table = document.add_table(rows=3, cols=2, style="Table Grid")
# table.style.bg.color.rgb = RGBColor(255, 0, 0)
# 开启高度不匹配
table.rows[0].hight_mismatch = True
# 开启宽度不匹配
table.cell(0, 0).width_mismatch = True
# 设置列 高 宽 注释:有时有用有时候又没用 不需要自行注释
for topIndex in range(0, 3):
# table.rows[topIndex].hight = Cm(100000.23)
table.cell(topIndex, 0).width = Cm(7.53)
table.cell(topIndex, 1).hight = Cm(1.23)
# 填充表描述 左侧数据
leftComment(table)
# 填充表描述 右侧数据
rightComment(table, tableAndComment)
# 设置字体 大小
table.style.font.size = Pt(11)
# 中间插入空字符串防止两个表组合在一起
document.add_paragraph("")
# 创建表 根据获取的数据长度+1行 7列 实线
table1 = document.add_table(rows=len(dbAll) + 1, cols=7, style="Table Grid")
# 开启高度不匹配
table1.rows[0].hight_mismatch = True
# 开启宽度不匹配
table1.cell(0, 0).width_mismatch = True
# 设置列 高 宽 注释:有时有用有时候又没用
for indexs in range(0, len(dbAll) + 1):
# table1.rows[indexs].hight = Cm(10.88)
for x in range(0, 7):
table1.cell(indexs, x).width = Cm(2.11)
table1.cell(indexs, x).hight = Cm(1.33)
# 表头填充
topComment(table1)
# 游标来记录操作行
dbLine = 1
for db1 in dbAll:
cell = table1.cell(dbLine, 0)
# 设置单元格文本
cell.text = str(dbLine)
cell = table1.cell(dbLine, 1)
# 设置单元格文本
cell.text = db1["列名"]
cell = table1.cell(dbLine, 2)
# 设置单元格文本
text1 = db1["数据类型"]
cell.text = db1["数据类型"]
splitStr = text1.split('(')
# 拆分数据长度注释
lenStr = ""
if len(splitStr) > 1:
lenStr = splitStr[1].split(")")
cell = table1.cell(dbLine, 3)
# 设置单元格文本
cell.text = lenStr
cell = table1.cell(dbLine, 4)
# 设置单元格文本
cell.text = db1["是否为空"]
cell = table1.cell(dbLine, 5)
# 设置单元格文本
cell.text = db1["备注"]
cell = table1.cell(dbLine, 6)
# 设置单元格文本
# 是否是主键判断 这里只适合每个表的第一列都是主键的操作,可以自行修改
isKey = "Y" if dbLine == 1 else "N"
cell.text = isKey
table1.style.font.name = '宋体'
table1.style.font.size = Pt(11)
dbLine += 1
levelLine += 1
# 目录地址根据需要自行修改,这里是导入到脚本统计目录下
document.save(r"filename.docx")