最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python實現(xiàn)動態(tài)生成系統(tǒng)數(shù)據庫設計到Word文檔

 更新時間:2023年06月25日 14:53:32   作者:李白的手機  
這篇文章主要為大家詳細介紹了如何利用Python實現(xiàn)填寫相關數(shù)據庫信息后,生成系統(tǒng)數(shù)據庫設計到word文檔,文中示例代碼講解詳細,感興趣的小伙伴可以了解一下

背景

經常需要交付一些系統(tǒng)文檔而且基本都是word的,其中又有系統(tǒng)數(shù)據庫介紹模塊, 看著數(shù)據庫里的幾百張表于是我開始懷疑人生, 所以咱手寫一個

涉及知識

  • pymysql 操作數(shù)據庫
  • tkinter GUI圖形庫
  • threading 線程
  • queue 阻塞隊列
  • pandas 數(shù)據計算模型(DataFame)
  • python-docx 操作word文檔庫

1、功能介紹

填寫相關數(shù)據庫信息后, 支持生成系統(tǒng)數(shù)據庫設計到word文檔節(jié)省寫文檔時間

  • 支持按自定義SQL結果導出
  • 支持導出所有表結構信息
  • 支持導出數(shù)據庫表清單
  • 支持測試連接

界面如下:

1.1 自定義SQL導出

在文本框內輸入sql,然后勾選導出模式為 自定義SQL, 最后點擊導出,生成word文檔如下。 會將該sq的執(zhí)行結果導出到word的表格

在自定義SQL模式時, 如果勾選了對所有表執(zhí)行一遍, 并且配置了模版變量 #{tableName}. 則會遍歷所有表執(zhí)行一遍該模版SQL, 如下圖。邏輯就是會先獲取該數(shù)據庫的所有表,然后遍歷執(zhí)行該模版sql并且替換模版變量#{tableName}, 最后將每次sql的執(zhí)行結果導出到word的表格里面。

最終結果:

1.2 導出所有表結構

勾選導出模式為表結構,生成word文檔如下。 邏輯是導出數(shù)據庫的所有的表結構到word的表格。 這個通過自定義SQL模式也可實現(xiàn),現(xiàn)在不過相當于內置了一些常用的模式。

1.3 導出數(shù)據庫表清單

勾選導出模式為表清單,生成word文檔如下, 就是將數(shù)據庫包含哪些表生成一份清單導出。

2、 代碼實現(xiàn)

import queue
import threading
import time
import traceback
from tkinter import Tk, Button, messagebox, Label, Frame, Entry, IntVar, Radiobutton, StringVar, \
    constants, filedialog, Text, font, Scrollbar, BooleanVar, Checkbutton
from tkinter.font import Font
from tkinter.messagebox import showinfo, showerror
from tkinter.ttk import Progressbar
from enum import Enum
import logging
from pymysql import OperationalError
class MsgEnum(Enum):
    """
        消息類型枚舉
    """
    START = 0
    STOP = 1
    EXIT = 3
class InputValue:
    def __init__(self, host, port, user, password, database, sql,calc_mode,isAllTable):
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.database = database
        self.sql = sql
        self.calc_mode = calc_mode
        self.isAllTable = isAllTable
class GuiTempldate:
    class Cache:
        RUNING = False
    def __init__(self) -> None:
        # 1、Gui消息隊列
        self.msg_center = MsgCenter(self)
        # 2、窗口設置
        self.root = Tk()
        self.root.title("數(shù)據庫導出工具")
        # self.root.wm_resizable(False, False) # 設置窗口大小不可拉伸
        self.root.geometry('600x700+500+200')  # 設置窗口: 寬 x 高 + 窗口位置x坐標 + 窗口位置y坐標
        self.root.protocol("WM_DELETE_WINDOW", self.close_event)
        # 4、初始化各個組件和布局
        self.initGui()
    def initGui(self):
        # 1- 標簽
        text_str = """版本: 1.0.0
        #author burukeyou
        #說明:
            1) 支持導出數(shù)據庫所有表結構信息
            2)支持導出數(shù)據庫表清單
            3)支持自定義sql導出
        """
        Label(self.root, text=text_str, justify='left', fg='red').pack(anchor=constants.W)
        # 4- 文本框
        fm02 = Frame(self.root)
        self.ip_address = StringVar(value="localhost:3306")
        fm02.pack(anchor=constants.W, fill=constants.X)
        Label(fm02, text='服務器地址 ').pack(side=constants.LEFT)
        self.name_btn = Entry(fm02, width=40, textvariable=self.ip_address)
        self.name_btn.pack(side=constants.RIGHT)
        # 4- 文本框
        fm02 = Frame(self.root)
        self.user_name = StringVar(value="root")
        fm02.pack(anchor=constants.W, fill=constants.X)
        Label(fm02, text='帳號').pack(side=constants.LEFT)
        self.name_btn = Entry(fm02, width=40, textvariable=self.user_name)
        self.name_btn.pack(side=constants.RIGHT)
        # 4- 文本框
        fm02 = Frame(self.root)
        self.password = StringVar(value="123456")
        fm02.pack(anchor=constants.W, fill=constants.X)
        Label(fm02, text='密碼').pack(side=constants.LEFT)
        self.name_btn = Entry(fm02, width=40, textvariable=self.password)
        self.name_btn.pack(side=constants.RIGHT)
        # 4- 文本框
        fm02 = Frame(self.root)
        self.database = StringVar(value="")
        fm02.pack(anchor=constants.W, fill=constants.X)
        Label(fm02, text='數(shù)據庫').pack(side=constants.LEFT)
        self.name_btn = Entry(fm02, width=40, textvariable=self.database)
        self.name_btn.pack(side=constants.RIGHT)
        # 3- 單選框
        self.mode_var = IntVar(value=1)
        fm01 = Frame(self.root)  # , bg='blue'
        fm01.pack(anchor=constants.W)
        Label(fm01, text='導出模式').grid(row=0, column=0, sticky='W')
        Radiobutton(fm01, text='表結構', variable=self.mode_var, value=1).grid(row=0, column=1, sticky='E', padx=40)
        Radiobutton(fm01, text='表清單', variable=self.mode_var, value=2).grid(row=0, column=2, sticky='E', padx=40)
        Radiobutton(fm01, text='自定義SQL', variable=self.mode_var, value=3).grid(row=0, column=3, sticky='E', padx=40)
        # 5- 勾選框
        self.is_all_flag = BooleanVar()
        self.is_all_table_btn = Checkbutton(self.root, variable=self.is_all_flag, text='所有表執(zhí)行一遍(自定義SQL可使用模版變量#{tableName})', onvalue=True, offvalue=False)
        self.is_all_table_btn.pack(anchor=constants.W)
        # 9- 多行文本框
        Label(self.root, text='自定義SQL輸入').pack(anchor=constants.W)
        fm22 = Frame(self.root)
        fm22.pack(anchor=constants.W, fill=constants.X)
        scroll = Scrollbar(fm22)
        scroll.pack(side=constants.RIGHT, fill=constants.Y)
        ft = Font(family='宋體', size=14, weight=font.BOLD)
        self.text_btn = Text(fm22, height=12, fg="black", font=ft, bg="white", insertbackground="black")
        self.text_btn.pack(side=constants.LEFT)
        # text 聯(lián)動 scroll
        scroll.config(command=self.text_btn.yview)
        self.text_btn.config(yscrollcommand=scroll.set)
        # 進度條
        self.progressbar = Progressbar(self.root, length=600, mode="determinate", orient=constants.HORIZONTAL)
        self.progressbar.pack(anchor=constants.W)
        self.progressbar['maximum'] = 100
        # 10、開始結束按鈕
        fm06 = Frame(self.root)
        fm06.pack(side=constants.BOTTOM)
        self.start_btn = Button(fm06, text="導出", width=6, height=1, command=self.start_event)
        self.start_btn.grid(row=0, column=0, sticky='W', padx=20, pady=20)
        self.stop_btn = Button(fm06, text="停止", width=6, height=1, command=self.stop_event)
        self.stop_btn.grid(row=0, column=1, sticky='E', padx=20, pady=20)
        self.test_btn = Button(fm06, text="測試連接", width=6, height=1, command=self.test_connection)
        self.test_btn.grid(row=0, column=2, sticky='E', padx=20, pady=20)
    def start_event(self):
        self.msg_center.put(MsgEnum.START)
        self.Cache.RUNING = True
        self.main_calc_thread: threading.Thread = threading.Thread(target=start_clac, args=(self,))
        self.main_calc_thread.start()
    def stop_event(self):
        self.msg_center.put(MsgEnum.STOP)
        self.Cache.RUNING = False
    def close_event(self):
        # 關閉窗口
        if self.Cache.RUNING and not messagebox.askokcancel("警告", "任務還在執(zhí)行中,確定要關閉嗎?"):
            return
        self.root.destroy()
        self.msg_center.put(MsgEnum.EXIT)
    def test_connection(self) -> bool:
        input_value = self.getInputValue()
        if not checkParam(input_value):
            return False
        conn = None
        try:
            conn = connectDB(input_value)
            showinfo(message="測試連接成功")
            return True
        except OperationalError as e:
            showerror(message="測試連接數(shù)據庫失敗,請確認數(shù)據庫信息是否正確。 \n" + str(e))
        finally:
            if conn:
                conn.close()
    def showUI(self):
        # 啟動消息隊列
        threading.Thread(target=self.msg_center.mainloop).start()
        # 這個方法會循環(huán)阻塞住,監(jiān)聽gui的事件,得放到主線程最后
        self.root.mainloop()
    def getInputValue(self) -> InputValue:
        ipaddress: str = self.ip_address.get().strip()
        if ipaddress == "" or ipaddress.find(":") < 0:
            showerror(message="請輸入正確的ip地址")
            return
        ip = ipaddress.split(":")[0].strip()
        port = ipaddress.split(":")[1].strip()
        database = self.database.get().strip()
        user_name = self.user_name.get().strip()
        password = self.password.get().strip()
        calc_mode = self.mode_var.get()
        custom_sql = self.text_btn.get("1.0", "end-1c").strip()
        isAllTable: bool = self.is_all_flag.get()
        return InputValue(ip, port, user_name, password,database, custom_sql,calc_mode,isAllTable)
def start_clac(gui: GuiTempldate):
    try:
        # 實際計算任務
        start_demo(gui)
    finally:
        # 發(fā)布結束事件
        gui.stop_event()
class MsgCenter:
    """
        消息隊列
            主要處理窗口控件消息
    """
    def __init__(self, obj: GuiTempldate) -> None:
        self.queue = queue.Queue()
        self.obj = obj
    def put(self, msg: Enum):
        self.queue.put(msg)
    def mainloop(self):
        while True:
            try:
                # 阻塞獲取消息
                msg = self.queue.get()
                print("消費消息: {}".format(msg))
                if msg == MsgEnum.START:
                    MsgStrategy.start_strategy(self.obj)
                elif msg == MsgEnum.STOP:
                    MsgStrategy.stop_strategy(self.obj)
                elif msg == MsgEnum.EXIT:
                    break
                else:
                    pass
            except queue.Empty:
                traceback.print_exc()
class MsgStrategy:
    @classmethod
    def start_strategy(cls, gui: GuiTempldate):
        gui.start_btn.config(state=constants.DISABLED)
        gui.stop_btn.config(state=constants.NORMAL)
        #
        gui.progressbar['value'] = 0
        for i in range(100):
            time.sleep(0.1)
            gui.progressbar['value'] += 1
            if i >= 50:
                gui.progressbar['value'] = 100
                gui.root.update()
                break
            gui.root.update()
    @classmethod
    def stop_strategy(cls, gui: GuiTempldate):
        gui.start_btn.config(state=constants.NORMAL)
        gui.stop_btn.config(state=constants.DISABLED)
# ===============================業(yè)務邏輯 ======================================================
from typing import List
import pymysql
import pandas as pd
from docx import Document
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
from datetime import datetime
from docx.table import Table, _Cell
def checkParam(input_value: InputValue) -> bool:
    if input_value.database == "" or input_value.user == "" or input_value.password == "" or input_value.host == "" or input_value.port == "":
        showerror(message="請?zhí)顚懲暾臄?shù)據庫連接參數(shù)")
        return False
    return True
def connectDB(input_value: InputValue):
     return pymysql.connect(host=input_value.host,
                            user=input_value.user,
                            password=input_value.password,
                            db=input_value.database,
                            port=int(input_value.port), charset="utf8")
def start_demo(gui: GuiTempldate):
    """ 自定義計算任務
    :param gui:             gui組件對象
    :return:
    """
    input_value = gui.getInputValue()
    # 校驗參數(shù)
    if not checkParam:
        return
    conn = None
    try:
        conn: pymysql.Connection = connectDB(input_value)
        print("建立連接成功")
        download(conn, input_value)
    except OperationalError as e:
        logging.error(e)
        showerror(message="連接數(shù)據庫失敗,請確認數(shù)據庫信息是否正確")
    except Exception as e1:
        # 打印堆棧信息
        e1.with_traceback(None)
        showerror(message="導出失敗")
    finally:
        if conn is not None:
            conn.close()
            print("關閉連接成功")
"""
    表結構SQL
"""
def tableSchemaSql(table_name,dataBase):
   return f"""
   select ORDINAL_POSITION 序號,
    COLUMN_NAME 字段名,
    COLUMN_TYPE 字段類型,
    -- DATA_TYPE 字段類型,
    -- CHARACTER_MAXIMUM_LENGTH 長度,
    -- IS_NULLABLE 是否為空,
    case when COLUMN_DEFAULT is null then '無' else COLUMN_DEFAULT end 默認值,
    COLUMN_COMMENT 字段說明
    FROM
    INFORMATION_SCHEMA.COLUMNS
    where
    table_schema ='{dataBase}'
    and table_name = '{table_name}';
   """
"""
    數(shù)據庫表清單SQL
"""
def databaseTableListSql(database):
    return f"""select table_name as '表名',TABLE_COMMENT '表中文名稱','業(yè)務表',TABLE_COMMENT '說明'
               from information_schema.tables
               where table_schema='{database}' and  LOWER(table_type) ='base table'
    """
def readAllTableToDataFrame(conn,dataBase) -> dict:
    # 獲取所有表的信息
    tables = pd.read_sql_query("SHOW TABLES;", conn)
    df_map = {}
    for _, table in tables.iterrows():
        table_name = table[0]
        if table_name is None or table_name == "":
            continue
        sql = tableSchemaSql(table_name,dataBase)
        df = pd.read_sql_query(sql, conn)
        df = df.reset_index(drop=True)
        df.index = df.index + 1
        df_map[table_name] = df
    return df_map
def readDataBaseTableListToDataFrame(conn, dataBase):
    df_map = {}
    sql = databaseTableListSql(dataBase)
    df = pd.read_sql_query(sql, conn)
    df = df.reset_index(drop=True)
    df.index = df.index + 1
    df_map["tmp"] = df
    return df_map
def readByCustomSqlToDataFrame(conn, input_value):
    # sql模版
    sql = input_value.sql
    # 獲取所有表的信息
    tables = pd.read_sql_query("SHOW TABLES;", conn)
    df_map = {}
    for _, table in tables.iterrows():
        table_name = table[0]
        if table_name is None or table_name == "":
            continue
        # 替換變量名 #{taleName}
        tmp_sql = sql.replace("#{tableName}", table_name)
        df = pd.read_sql_query(tmp_sql, conn)
        df = df.reset_index(drop=True)
        df.index = df.index + 1
        df_map[table_name] = df
    return df_map
def downloadToWord(df_map, save_path, heading):
    # 創(chuàng)建Word文檔
    doc = Document()
    for table_name in df_map:
        df = df_map[table_name]
        # 添加標題
        if heading:
            doc.add_heading(heading, level=3)
        else:
            doc.add_heading(f"【{table_name}表】", level=3)
        # 轉成list表格數(shù)據
        table_data: List = [df.columns.tolist()] + df.values.tolist()
        # 創(chuàng)建 rows x col 表格
        table: Table = doc.add_table(rows=len(table_data), cols=len(table_data[0]))
        # 設置表格樣式
        table.style = "Table Grid"
        # 設置表格字體和大小
        #table.style.font.name = "宋體"
        #table.style.font.size = 5
        # 填充表格內容
        for i, row in enumerate(table_data):
            for j, value in enumerate(row):
                cell: _Cell = table.cell(i, j)
                cell.text = str(value)
                # 設置第一行
                if i == 0:
                    # 設置文本加粗
                    for run in cell.paragraphs[0].runs:
                        run.bold = True
        #  設置第一行背景色為淺灰色D9D9D9
        for i, cell in enumerate(table.rows[0].cells):
            shading_elm_1 = parse_xml(r'<w:shd {} w:fill="D9D9D9"/>'.format(nsdecls('w')))
            cell._tc.get_or_add_tcPr().append(shading_elm_1)
    # 保存Word文檔
    doc.save(save_path)
    print("導出" + save_path + "成功")
def download(conn, input_value):
    dataBase = input_value.database
    calc_mode = input_value.calc_mode
    custom_sql = input_value.sql
    # 讀取所有表結構到DataFrame
    heading = None
    df_map = {}
    if calc_mode == 1:
        # 所有表結構
        print("執(zhí)行模式1")
        df_map = readAllTableToDataFrame(conn, dataBase)
    elif calc_mode == 2:
        # 表清單
        print("執(zhí)行模式2")
        df_map = readDataBaseTableListToDataFrame(conn, dataBase)
        heading = f"【{dataBase}數(shù)據庫表清單】"
    else:
        # 自定義sql
        if custom_sql is None or custom_sql == "":
            showinfo("", "請輸入自定義SQL")
            return
        # 配置了都執(zhí)行一遍并且sql模版真中包含#{tableName}變量
        if input_value.isAllTable == True and custom_sql.find("#{tableName}") != -1:
            print("自定義SQL對所有表執(zhí)行一遍")
            df_map = readByCustomSqlToDataFrame(conn, input_value)
        else:
            df = pd.read_sql_query(custom_sql, conn)
            df_map["tmp"] = df
            heading = f"【{dataBase}自定義SQL數(shù)據】"
    # 選擇導出位置
    now = datetime.now().strftime("%y%m%d%H%M%S")
    file_name = dataBase + f"數(shù)據庫數(shù)據-{now}.docx"
    save_path = filedialog.asksaveasfilename(title=u'保存文件', filetypes=[("word文件", ".docx")], initialfile=file_name)
    print("保存位置目錄", save_path)
    if save_path == "" or save_path is None:
        return
    # 導出到word
    downloadToWord(df_map, save_path, heading)
    showinfo("", "導出成功")
if __name__ == '__main__':
    gui = GuiTempldate()
    gui.showUI()

代碼說明:

  • GuiTempldate: 將所有的圖形按鈕控件等都封裝成該對象, 一個該對象代表一個窗口, 并且封裝相關按鈕事件
  • MsgCenter: 消息隊列, 每個GuiTempldate 內部都對應一個消息隊列, 用作異步,解耦主流程事件防止阻塞只能串行執(zhí)行事件, 打個比方因為一般窗口的按鈕都是都是可以隨便點的,不可能你點完這個按鈕后觸發(fā)了一些事件,然后你必須等這個事件執(zhí)行完才能操作下一個按鈕。 說白類似每次用一個新線程去異步執(zhí)行, 用消息隊列不過是線程池的效果。
  • 點擊導出后實際執(zhí)行的方法是 start_clac, 然后里面邏輯比較簡單都是導出的相關業(yè)務邏輯

以上就是Python實現(xiàn)動態(tài)生成系統(tǒng)數(shù)據庫設計到Word文檔的詳細內容,更多關于Python生成數(shù)據庫設計到Word的資料請關注腳本之家其它相關文章!

相關文章

  • Django異步任務之Celery的基本使用

    Django異步任務之Celery的基本使用

    這篇文章主要給大家介紹了關于Django異步任務之Celery使用的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Django具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-03-03
  • Linux-ubuntu16.04 Python3.5配置OpenCV3.2的方法

    Linux-ubuntu16.04 Python3.5配置OpenCV3.2的方法

    下面小編就為大家分享一篇Linux-ubuntu16.04 Python3.5配置OpenCV3.2的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-04-04
  • python字符串的index和find的區(qū)別詳解

    python字符串的index和find的區(qū)別詳解

    這篇文章主要介紹了python字符串的index和find的區(qū)別,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-06-06
  • Python腳本實現(xiàn)圖片文件批量命名

    Python腳本實現(xiàn)圖片文件批量命名

    這篇文章主要為大家詳細介紹了一個用python第三方庫pillow寫的批量處理圖片命名的腳本,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下
    2025-02-02
  • 零基礎寫python爬蟲之HTTP異常處理

    零基礎寫python爬蟲之HTTP異常處理

    我們在使用爬蟲來抓取網頁內容的時候,HTTP異常是必須要注意的一項,所以本文,我們來詳細探尋一下HTTP異常處理的相關內容,通過一些具體的實例來分析一下,非常的簡單,但是卻很實用。
    2014-11-11
  • 2018年Python值得關注的開源庫、工具和開發(fā)者(總結篇)

    2018年Python值得關注的開源庫、工具和開發(fā)者(總結篇)

    本文給大家總結了2018年Python值得關注的開源庫、工具和開發(fā)者,需要的朋友可以參考下
    2018-01-01
  • PyCharm代碼格式調整方法

    PyCharm代碼格式調整方法

    今天小編就為大家分享一篇PyCharm代碼格式調整方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Pytorch distributed 多卡并行載入模型操作

    Pytorch distributed 多卡并行載入模型操作

    這篇文章主要介紹了Pytorch distributed 多卡并行載入模型操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • 10個Python常用的損失函數(shù)及代碼實現(xiàn)分享

    10個Python常用的損失函數(shù)及代碼實現(xiàn)分享

    損失函數(shù)是一種衡量模型與數(shù)據吻合程度的算法。損失函數(shù)測量實際測量值和預測值之間差距的一種方式。本文為大家總結了10個常用的損失函數(shù)及Python代碼實現(xiàn),需要的可以參考一下
    2022-09-09
  • Pandas DataFrame中實現(xiàn)取單個值的讀取和修改

    Pandas DataFrame中實現(xiàn)取單個值的讀取和修改

    這篇文章主要介紹了Pandas DataFrame中實現(xiàn)取單個值的讀取和修改,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10

最新評論

彭州市| 育儿| 文水县| 江油市| 龙岩市| 阜南县| 阜南县| 高雄市| 岳阳市| 郑州市| 靖西县| 正定县| 枣阳市| 五华县| 静宁县| 漠河县| 泉州市| 漳州市| 邹城市| 甘肃省| 文昌市| 浦县| 玉溪市| 乌兰县| 武义县| 方山县| 廊坊市| 大港区| 肃宁县| 资阳市| 涟源市| 呼和浩特市| 绍兴市| 宁城县| 鹤峰县| 扬中市| 梁河县| 诸暨市| 江孜县| 海门市| 宕昌县|