prompt_toolkit是一个专门用于实现交互式终端工具的python库,它支持代码补全,自动提示,查询历史,语法高亮,可以让你快速的实现一个可交互的终端工具,这在需要交互的场景下非常受欢迎,本文将带你实现一个mysql客户端交互工具,实现与mysql服务器的交互。
首先,进行安装
pip install prompt_toolkit
既然是交互式工具,就必须能够做到与用户交互,prompt函数可以接收用户在终端的输入
from prompt_toolkit import prompt
def main():
    text = prompt("> ")
    print('You entered:', text)
if __name__ == '__main__':
    main()
启动程序后,在终端输入hello world, 得到"You entered:hello world" 的输出同时程序运行结束。实践中,与用户的交互是持续的,直到用户输入退出的命令,因此,需要在程序中使用while循环不停的接收用户的输入
from prompt_toolkit import prompt
def main():
    while True:
        text = prompt("> ")
        if text == 'quit':
            print("退出程序")
            break
        print('You entered:', text)
if __name__ == '__main__':
    main()
为了能够与数据库进行交互,需要在程序里创建一个数据库的连接,为了降低难度,创建数据库连接所需要的参数直接硬编码在脚本里, 我使用mysql-connector库与mysql进行交互,安装命令
pip install mysql-connector
创建mysql的连接
import mysql.connector
mydb = mysql.connector.connect(
    host="101.201.37.248",  # 数据库主机地址
    user="manager",  # 数据库用户名
    passwd="3243Wdj!$dkwf44",  # 数据库密码
    port=1348,
)
mycursor = mydb.cursor(dictionary=True)
from prompt_toolkit import prompt
import mysql.connector
mydb = mysql.connector.connect(
    host="101.201.37.248",  # 数据库主机地址
    user="manager",  # 数据库用户名
    passwd="3243Wdj!$dkwf44",  # 数据库密码
    port=1348,
)
mycursor = mydb.cursor(dictionary=True)
def main():
    while True:
        text = prompt("> ")
        if text == 'quit':
            print("退出程序")
            break
        try:
            mycursor.execute(text)
            datas = mycursor.fetchall()
        except Exception as e:
            print(e)
        else:
            print(datas)
if __name__ == '__main__':
    main()
启动程序,在终端里输入命令并回车
show databases
程序将执行show databases命令并返回结果
[{'Database': 'information_schema'}, {'Database': 'automated_testing'}, {'Database': 'stumanager'}]
上面的逻辑是不完善的,我们所执行的sql语句大致可分为两类,一类是有返回值的比如select语句,一类是没有返回值的比如insert语句,我使用了一个简单的方法来区分它们
def main():
    while True:
        text = prompt("> ")
        if text == 'quit':
            print("退出程序")
            break
        try:
            mycursor.execute(text)
            rowcount = mycursor.rowcount
            if rowcount >= 0:
                mydb.commit()
                print(f"{rowcount}行数据受影响")
            else:
                data = mycursor.fetchall()
                print(data)
        except Exception as e:
            print(e)
mycursor.rowcount是受到sql语句影响的条数,如果这个值大于等于0说明是在执行修改删除动作,如果是-1,则表示是查询类操作。
使用语法高亮能让我们的终端工具更加漂亮,编写的sql语句中的关键字更加突出
from pygments.lexers import MySqlLexer
from prompt_toolkit.lexers import PygmentsLexer
def main():
    while True:
        text = prompt("> ", lexer=PygmentsLexer(MySqlLexer))
下面是代码改动的部分
from prompt_toolkit.completion import Completer, Completion
class MySimpleCompleter(Completer):
    def get_completions(self, document, complete_event):
        completions = ['create', 'select', 'insert', 'drop',
                               'delete', 'from', 'where', 'table']
        word_before_cursor = document.get_word_before_cursor()
        completions = [c for c in completions if c.startswith(word_before_cursor)]
        for completion in completions:
            yield Completion(completion, start_position=-len(word_before_cursor))
            
def main():
    while True:
        text = prompt("> ", lexer=PygmentsLexer(MySqlLexer), completer=MySimpleCompleter())
下面是代码改动部分
from prompt_toolkit.history import FileHistory
def main():
    history = FileHistory('my_sql.txt')
    while True:
        text = prompt("> ", lexer=PygmentsLexer(MySqlLexer), completer=MySimpleCompleter(), history=history)
        
在终端输入的命令都会记录在my_sql.txt里,下一次启动程序时,通过键盘的上上下键就可以选择之前输入过的命令,实现快速输入
虽然前面实现了数据的查询,但是展示的数据很难阅读,接下来的目标是使用表格展示他们,实现
from prettytable import PrettyTable
def show_data(lst):
    if not lst:
        print("未查到数据")
        return
    data = lst[0]
    coumns = list(data.keys())
    table = PrettyTable(coumns)
    for row in lst:
        row = list(row.values())
        row = [str(item) for item in row]
        table.add_row(row)
    print(table)
    
import mysql.connector
from prompt_toolkit import prompt
from pygments.lexers import MySqlLexer
from prompt_toolkit.lexers import PygmentsLexer
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.history import FileHistory
from prettytable import PrettyTable
mydb = mysql.connector.connect(
    host="",  # 数据库主机地址
    user="",  # 数据库用户名
    passwd="",  # 数据库密码
    port=3306,
)
mycursor = mydb.cursor(dictionary=True)
class MySimpleCompleter(Completer):
    def get_completions(self, document, complete_event):
        completions = ['create', 'select', 'insert', 'drop',
                               'delete', 'from', 'where', 'table']
        word_before_cursor = document.get_word_before_cursor()
        completions = [c for c in completions if c.startswith(word_before_cursor)]
        for completion in completions:
            yield Completion(completion, start_position=-len(word_before_cursor))
def show_data(lst):
    if not lst:
        print("未查到数据")
        return
    data = lst[0]
    coumns = list(data.keys())
    table = PrettyTable(coumns)
    for row in lst:
        row = list(row.values())
        row = [str(item) for item in row]
        table.add_row(row)
    print(table)
def main():
    history = FileHistory('my_sql.txt')
    while True:
        text = prompt("> ", lexer=PygmentsLexer(MySqlLexer), completer=MySimpleCompleter(), history=history)
        if text == 'quit':
            print("退出程序")
            break
        try:
            mycursor.execute(text)
            rowcount = mycursor.rowcount
            if rowcount >= 0:
                mydb.commit()
                print(f"{rowcount}行数据受影响")
            else:
                data = mycursor.fetchall()
                show_data(data)
        except Exception as e:
            print(e)
if __name__ == '__main__':
    main()
效果图

 
            扫描关注, 与我技术互动
QQ交流群: 211426309
 
                        分享日常研究的python技术和遇到的问题及解决方案