postgreSQL 数据库字典导出工具

为满足项目验收文档需求,开发了一个基于Python的PostgreSQL数据字典导出工具。

废话不多说,先分享一下

软件截图

数据字典文件样式,文件格式为docx

软件源码

基于python开发,

import tkinter as tk
from tkinter import ttk, messagebox
from PIL import Image, ImageTk
import psycopg2
from docx import Documentclass ProfessionalDBConnector:def __init__(self, root):self.root = rootself.root.title("数据字典导出工具 v1.0")self.root.geometry("500x550")self.root.resizable(False, False)self.root.configure(bg="#f5f5f5")# 加载logotry:self.logo_img = ImageTk.PhotoImage(Image.open("logo.png").resize((100, 40)))logo_label = tk.Label(root, image=self.logo_img, bg="#f5f5f5")logo_label.grid(row=0, column=0, columnspan=2, pady=(20, 30))except:title_label = tk.Label(root, text="PostgreSql数据字典导出工具", font=("微软雅黑", 16, "bold"), bg="#f5f5f5", fg="#333")title_label.grid(row=0, column=0, columnspan=2, pady=(20, 30))# 输入框样式style = ttk.Style()style.configure("TLabel", background="#f5f5f5", font=("微软雅黑", 10))style.configure("TEntry", font=("微软雅黑", 10), padding=5)style.configure("TButton", font=("微软雅黑", 10, "bold"), padding=5)# 输入框标签fields = ["主机:", "端口:", "用户名:", "密码:", "数据库名:"]self.entries = {}for i, field in enumerate(fields):ttk.Label(root, text=field).grid(row=i + 1, column=0, padx=20, pady=5, sticky="e")entry = ttk.Entry(root)if field == "密码:":entry = ttk.Entry(root, show="*")entry.grid(row=i + 1, column=1, padx=10, pady=5, sticky="ew")self.entries[field[:-1]] = entry# 连接按钮self.connect_test_btn = tk.Button(root, text="测试连接", command=self.connect_test_db,# 设置按钮的背景颜色为绿色bg="#4CAF50",# 设置按钮的前景(文本)颜色为白色fg="white",# 设置按钮在按下状态时的背景颜色activebackground="#45a049",# 设置按钮文本的字体和样式font=("微软雅黑", 10, "bold"),# 设置按钮内部x轴方向的填充padx=15,# 设置按钮内部y轴方向的填充pady=5,# 设置按钮的边框样式为平的,无边框relief="flat",# 设置按钮的边框宽度为0,与relief参数共同作用实现无边框效果bd=0,# 设置鼠标悬停在按钮上时的光标样式为手型cursor="hand2")# 创建导出按钮组件# 该按钮用于触发导出数据库功能,其具体功能通过command参数关联的self.export_db方法实现self.export_dictionary_btn = tk.Button(root, text="导出数据字典", command=self.export_dictionary,bg="#4CAF50",fg="white",activebackground="#45a049",font=("微软雅黑", 10, "bold"),padx=15,pady=5,relief="flat",bd=0,cursor="hand2")self.connect_test_btn.grid(row=6, column=0, columnspan=2, pady=20)self.export_dictionary_btn.grid(row=7, column=0, columnspan=2, pady=20)# 底部署名和版权信息footer_frame = tk.Frame(root, bg="#e0e0e0")footer_frame.grid(row=9, column=0, columnspan=2, sticky="ew", pady=(10, 0))tk.Label(footer_frame, text="© 2025 数据库工具 | 开发人员: guozs",bg="#e0e0e0", fg="#666", font=("微软雅黑", 8)).pack(pady=5)# 配置网格权重root.columnconfigure(1, weight=1)def connect_test_db(self):try:conn = self.getConn()cursor = conn.cursor()cursor.execute("select version()")result = cursor.fetchall()if result is not None:messagebox.showinfo("连接成功", f"数据库版本:{result}")conn.close()else:messagebox.showinfo("连接失败")except Exception as e:messagebox.showerror("连接失败", f"错误: {str(e)}")def getConn(self):self.database = self.entries["数据库名"].get()if self.database == "":self.database = "abc"self.user = self.entries["用户名"].get()if self.user == "":self.user = "postgres"self.password = self.entries["密码"].get()if self.password == "":self.password = "123456"self.host = self.entries["主机"].get()if self.host == "":self.host = "127.0.0.1"self.port = self.entries["端口"].get()if self.port == "":self.port = "5432"conn = psycopg2.connect(database=self.database,user=self.user,password=self.password,host=self.host,port=int(self.port))return conndef export_dictionary(self):doc = Document()try:self.exportTableInfoToDocx(doc)messagebox.showinfo("成功", f"数据字典已导出")except Exception as e:messagebox.showerror("失败", f"错误: {str(e)}")def getTableList(self):conn = self.getConn()cur = conn.cursor()query = '''select A.schemaname,A.relname,obj_description ( B.relfilenode, 'pg_class' ) AS tablenamefrom pg_stat_user_tables as A,pg_class as BWHERE B.relname = A.relname  ORDER BYA.schemaname,A.relname'''cur.execute(query)tableList = cur.fetchall()conn.commit()cur.close()conn.close()return tableListdef getTableColumnByTableName(self, tableName):conn = self.getConn()cur = conn.cursor()tableName = "'" + tableName + "'"query = f'''SELECTd.relname AS relname,obj_description ( relfilenode, 'pg_class' ) AS tablename,attname AS field,CASEtypname WHEN '_bpchar' THEN'char' WHEN '_varchar' THEN'varchar' WHEN '_date' THEN'date' WHEN '_float8' THEN'float8' WHEN '_int4' THEN'int4' WHEN '_int8' THEN'int8' WHEN '_interval' THEN'interval' WHEN '_numeric' THEN'numeric' WHEN '_float4' THEN'float4' WHEN '_int2' THEN'smallint' WHEN '_text' THEN'text' WHEN '_time' THEN'time' WHEN '_timestamp' THEN'timestamp' WHEN '_timestamptz' THEN'timestamptz' END AS TYPE,CASEtypname WHEN '_bpchar' THENatttypmod - 4 WHEN '_varchar' THENatttypmod - 4 WHEN '_numeric' THEN( atttypmod - 4 ) / 65536 ELSE attlen END AS LENGTH,CASEtypname WHEN '_numeric' THEN( atttypmod - 4 ) % 65536 ELSE 0 END AS xs,CASEWHEN b.attnotnull = 't' THEN'不能为空' ELSE'' END AS NOTNULL,CASEWHEN ( SELECT COUNT ( * ) FROM pg_constraint WHERE conrelid = b.attrelid AND conkey [ 1 ]= attnum AND contype = 'p' ) > 0 THEN'主键' ELSE'' END AS zj,col_description ( b.attrelid, b.attnum ) AS COMMENT FROMpg_stat_user_tables AS A,pg_class AS d,pg_tables AS P,pg_attribute AS b,pg_type AS C WHEREA.relid = b.attrelid AND b.attnum > 0 AND b.atttypid = C.typelem AND substr( typname, 1, 1 ) = '_' AND P.tablename = d.relname AND d.relname = A.relname AND A.relname NOT LIKE'c%' AND A.relname NOT LIKE'S%' AND P.tablename = {tableName}ORDER BYA.schemaname,A.relname,attnum'''cur.execute(query)data = cur.fetchall()conn.commit()cur.close()conn.close()return datadef exportTableInfoToDocx(self, doc):tableList = self.getTableList()p = doc.add_paragraph('')table_explain = "数据字典"p.add_run(table_explain, style="Heading 1 Char")p = doc.add_paragraph('')table_explain = "数据库名:%s" % (self.database)p.add_run(table_explain, style="Heading 1 Char")p = doc.add_paragraph('')table_explain = "表汇总"p.add_run(table_explain, style="Heading 1 Char")table = doc.add_table(rows=1, cols=3)table.style = 'TableGrid'hdr_cells = table.rows[0].cellshdr_cells[0].text = '模式'hdr_cells[1].text = '表名'hdr_cells[2].text = '表注释'for tableInfo in tableList:new_cells = table.add_row().cellsnew_cells[0].text = tableInfo[0]new_cells[1].text = tableInfo[1]# 判断注释是否为空new_cells[2].text = getStr(tableInfo[2])  # if tableInfo[2] is None else tableInfo[2]p = doc.add_paragraph('')p = doc.add_paragraph('')p = doc.add_paragraph('')table_explain = "表详情"p.add_run(table_explain, style="Heading 1 Char")try:for tableInfo in tableList:tableName = tableInfo[1]tableComment = getStr(tableInfo[2])p = doc.add_paragraph('')table_explain = "表名:%s, 注解:%s" % (tableName, getStr(tableComment))  # tableName + ",注解:" + getInfo(tableComment) + ",对应数据库的表:"p = doc.add_paragraph('')p.add_run(table_explain, style="Heading 1 Char")table = doc.add_table(rows=1, cols=5)table.style = 'TableGrid'hdr_cells = table.rows[0].cellshdr_cells[0].text = '字段名'hdr_cells[1].text = '字段类型'hdr_cells[2].text = '允许为空'hdr_cells[3].text = 'PK'hdr_cells[4].text = '字段说明'tableColumnList = self.getTableColumnByTableName(tableInfo[1])for tableColumn in tableColumnList:new_cells = table.add_row().cellsnew_cells[0].text = getStr(tableColumn[2])new_cells[1].text = getStr(tableColumn[3])new_cells[2].text = getStr(tableColumn[6])new_cells[3].text = getStr(tableColumn[7])new_cells[4].text = getStr(tableColumn[8])except Exception as e:messagebox.showerror("失败", f"错误: {str(e)}")p = doc.add_paragraph('')doc.save('./' + self.database + '_数据字典.docx')def getStr(param):if param is None:return ""else:return paramif __name__ == "__main__":root = tk.Tk()app = ProfessionalDBConnector(root)root.mainloop()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/86379.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/86379.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AI解析】 CppNumericalSolvers:一个现代化的 C++17 纯头文件优化库 示例代码解析

一个轻量级仅头文件的 C17 库,提供针对(无)约束非线性函数及表达式模板的数值优化方法 https://github.com/PatWie/CppNumericalSolvers CppNumericalSolvers 库 include 目录下的文件及其功能说明 根目录文件 文件名功能说明function.h(主函…

第3篇:Gin的请求处理——获取客户端数据(Gin文件上传,接收JSON数据)

引言:Context是Gin的"瑞士军刀" 在Gin框架中,Context就像一把多功能的瑞士军刀,封装了所有与请求相关的操作。新手开发者常犯的错误是只把它当作参数传递的工具,却忽略了它强大的数据处理能力。 想象一个场景&#xf…

启动hardhat 项目,下载依赖的npm问题

Windows 环境 Hardhat 依赖安装问题排查指南 🚨 问题描述 在 Windows 环境下安装 Hardhat 项目依赖时,遇到以下错误: npm ERR! code ETARGET npm ERR! notarget No matching version found for nomicfoundation/edr^0.11.1. npm ERR! nota…

大数据里的拉链表:数据版本管理的时间胶囊

哈喽各位数据打工人~今天咱们来聊聊大数据领域一个超实用的神器 ——拉链表!听起来像时尚单品?NoNoNo,它可是数据仓库里管理历史数据的宝藏工具✨ 就算你是刚入门的小白也能轻松听懂,咱们全程少玩比喻多讲人话&#xf…

docker执行yum报错Could not resolve host: mirrorlist.centos.org

解决办法: -- 依次执行以下命令cd /etc/yum.repos.d/sed -i s|#baseurlhttp://mirror.centos.org|baseurlhttp://vault.centos.org|g /etc/yum.repos.d/CentOS-*sed -i s/mirrorlist/#mirrorlist/g /etc/yum.repos.d/CentOS-*yum update -yecho "export LC_ALL…

JVM OutOfMemoryError原因及排查解决方案

在Java后端开发中,java.lang.OutOfMemoryError(简称OOM)是一个令开发者头疼的异常。它通常意味着Java虚拟机(JVM)在尝试分配新对象时,发现堆中没有足够的空间来容纳该对象,或者其他内存区域耗尽…

吐槽之前后端合作开发

大家好,我是佳瑞,从事10多年java开发程序员,爆照一张,存活互联网。 也做过vue开发自己的网站,觉得前端是真比后端开发轻松很多,就是画页面调样式,打包发布,当然不说是高级源码修改…

Oracle LogMiner日志分析工具介绍

Oracle LogMiner日志分析工具介绍 LogMiner使用须知LogMiner字典使用online catalog作为日志挖掘字典使用redo日志文件作为日志挖掘字典使用文本文件作为日志挖掘字典Redo日志文件自动获取日志文件手动获取日志文件启动LogMiner进行分析V$LOGMNR_CONTENTS视图LogMiner使用须知 …

2-4 Dockerfile指令(个人笔记)

以下指令基于 ubuntu Dockerfile整体示例 From:设置基础镜像 Maintainer :镜像维护者信息 COPY/ADD:添加本地文件到镜像中 WorkDir:设置工作目录 Run:执行命令 CMD/EntryPoint:配置容器启动时执行的命令

Redis主从架构哨兵模式

文章目录 概述一、主从搭建实例二、主从同步原理三、哨兵架构3.1、搭建哨兵架构3.2、演示故障恢复3.3、哨兵日志 概述 在生产环境下,Redis通常不会单机部署,为了保证高可用性,通常使用主从模式或集群架构,同时也面临着一些问题&am…

基于深度学习yolov5的安全帽实时识别检测系统

摘要:在现代工业和建筑行业中,确保员工的安全是至关重要的一环。安全帽作为一项基础的个人防护设备,对于降低头部受伤的风险发挥着关键作用。然而,确保工作人员在施工现场始终正确佩戴安全帽并非易事。传统的人工检查方法不仅效率…

GitLab 18.1 发布 Runner、无效的个人访问令牌查看等功能,可升级体验!

GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…

量子计算与AI融合 - 企业级安全威胁应对

量子计算(QC)虽带来万亿级市场机遇(2025-2035年),但潜藏重大安全风险:可能破解现有加密系统,催生"现在窃取,未来解密"攻击。美国NIST已启动后量子加密标准,但技…

Excel:filter函数实现动态筛选的方法

filter的意思是“过滤、筛选”,动态筛选,FILTER()函数可以将对筛选区域内容,并将结果自动溢出生成一个新区域,以下是函数的使用方法: (一)情景:给定两列数据,我需要根据…

兰洋科技上合组织论坛发表专题分享,全球液冷布局引领绿色算力未来

2025年6月17-19日,中国—上海合作组织数字技术合作发展论坛在新疆克拉玛依市举办。作为第四次上海合作组织成员国信息通信技术发展部门负责人会议的配套会议,论坛以“数字化转型助力可持续发展,数字包容促进上合共同繁荣”为主题,…

LED-Merging: 无需训练的模型合并框架,兼顾LLM安全和性能!!

摘要:对预训练大型语言模型(LLMs)进行微调以适应特定任务,会带来巨大的计算和数据成本。虽然模型合并提供了一种无需训练的解决方案,用于整合多个特定任务的模型,但现有方法存在安全性与效用性之间的冲突&a…

火山引擎向量数据库 Milvus 版正式开放

资料来源:火山引擎-开发者社区 随着AI技术的不断演进发展,非结构化数据也迎来了爆发式的增长。Milvus作为一款为大规模向量相似度搜索和 AI 应用开发设计的开源向量数据库系统,目前已在业界占据领导地位。当前 Milvus 已经被 5,000 家企业所…

SQL SERVER存储过程

什么是存储过程 SQL 存储过程(Stored Procedure)是一个在数据库中预编译并存储的一组 SQL 语句。它们可以包含查询、插入、更新、删除等数据库操作,甚至包括控制流语句(如条件判断、循环等)。存储过程可以通过调用来执…

Lombok注解 - 提高Java开发效率

01 繁琐编码 初入 Java 开发领域时,编写实体类的琐碎经历想必各位都深有感触。 每当创建一个实体类,铺天盖地的 getter、setter、toString 方法接踵而至,手指在键盘上频繁敲击,酸痛不已。 而 Lombok 这一神器的出现&#xff0c…

Linux修改uboot启动延时方法详细攻略,触觉智能RK3568开发板演示

修改uboot延时 首先查找defconfig文件 ./build.sh uboot #通过编译日志查看使用的defconfig文件ls u-boot/configs/*3568* #在SDK根目录下执行该操作 如图标注处就是所使用的u-boot配置文件。 然后修改延时数: vim u-boot/configs/rk3568_defconfig 将CONFIG_BOO…