• wxFormBuilder + Python 工具开发第二章-日记本工具数据连接与展示


    目录

     

    前言

    一、代码目录层级

    二、数据库

    三、数据表设计

    四、展示数据


    前言

    上一章节已经介绍了如何将程序主窗口设计好生成python代码,运行成功的展示了窗体。

    上一章内容地址:

    wxFormBuilder + Python 工具开发第一章-拖出日记本图形界面_魂尾ac的博客-CSDN博客

    这一章节将会介绍如何将代码目录架构定好,实现树与文章从数据库展示到前端窗体的内容

     功能与内容:

            数据库选型

            设计数据表

            实现数据IO

            展示树节点

            切换展示文章

            实现后基本功能测试

    本节最终效果图

    文中   wxFormBuilder   均简化为  wxF  代替

    一、代码目录层级

    代码目录设计为

    NodeBook

            manage

            template

           

    NodeBook为日记本项目目录,template为wxF生成的图形界面代码目录,manage是一些继承template里图界面代码类的类文件、数据库管理代码文件、以及其它逻辑代码的目录,后面还会有一个目录存放本地数据库

    1、新增名为template的pkg目录,将图形界面代码移入

            

    2、新增名为manage的pkg目录,在其下新增newWindow.py文件,将runMain里的MainFrame派生类移入其中

    PS:注释MainFrame导入头会变成:from NodeBook.template.noname import MainFrame

    3、在runMain.py中去掉MainFrame派生类的代码,添加NewWindow的导入头:

    from NodeBook.manage.newWindow import NewWindow

    runMain.py始终是项目代码运行入口。

           

    4、运行,检查代码是否正常

    二、数据库

    小工具要使用的数据应该是一个跟着工具走,本地的,开源的,Sqlite刚好满足这样一个需求;许多开发手机app小工具的都使用它作为数据库。

    1、Sqlite下载

    在https://www.sqlite.org/download.html网站下载

            

    解压sqlite-tools-win32-x86-3390200.zip

    2、建库

    打开sqlite.exe文件

    输入命令:.open notebook.db 生成数据库

    3、建表

    使用navicat连接notebook.db(navicat怎么连sqlite, 百度学习一下)

    建一个user表,表里有accout、password字段,建表SQL如下:
    create table user(

    id INTEGER primary key autoincrement,

    account VARCHAR not null,

       password VARCHAR not null

    )

    在user表里添加几条数据供python调试

    4、python连接notebook.db库

            1)在代码目录新增一个database目录,将notebook.db 拷贝到database目录下。

      

            2)manage目录下新增一个sqliteio.py文件,

            3)先获取一下notebook.db的绝对路径,编写代码如下

    1. import os
    2. import sqlite3
    3. #获取上一层目录的绝对路径
    4. par_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    5. #获取database绝对路径
    6. dpath = os.path.join(par_path, 'database')
    7. #获取notebook.db的绝对路径
    8. nbpath = os.path.join(dpath, 'notebook.db')
    9. print(nbpath)

            执行结果:

            4)连接数据,读写user数据,编写代码如下

    1. #连接数据
    2. conn = sqlite3.connect(nbpath)
    3. #获取游标
    4. cur = conn.cursor()
    5. #执行查询SQL语句
    6. cur.execute('select * from user;')
    7. #遍历查出的数据,fetchall()即获取查出所有数据的列表
    8. for row in cur.fetchall():
    9.     print(row)
    10. #执行插入数据
    11. cur.execute('insert into user(account, password) values("xiaotian","qwert1234")')
    12. print('-------插入数据后---- 重新查询------- ')
    13. #重新查询
    14. cur.execute('select * from user;')
    15. #遍历查出的数据,fetchall()即获取查出所有数据的列表
    16. for row in cur.fetchall():
    17.     print(row)
    18. #关闭游标、关闭数据库连接
    19. cur.close()
    20. conn.close()

            执行结果

            Sqlite基础操作暂时告一段落,后面开始做Notebook数据库开的正式内容

    三、数据表设计

    1、表设计

            日记本,日期与名称,做一个树节点表,有id,父id,节点名称等等;再做一个文章表,有树节点外键,文章标题,文章内容等等。

    树表:treenodes

    字段

    类型

    长度

    可否为空

    描述

    id

    主键自增

    tree_note

    char

    200

    节点名称

    parent_id

    Int

    父节点id

    Is_delete

    int

    删除标识,默认为0未删除, 1为删除

    create_time

    Data_time

    创建时间

    updata_time

    Data_time

    更新时间

    文章表:articles

    字段

    类型

    长度

    可否为空

    描述

    id

    主键自增

    tree_id

    treenodes外键

    name

    vchar

    200

    文章名称

    content

    text

    文章内容

    Is_delete

    int

    删除标识,默认为0未删除, 1为删除

    create_time

    Data_time

    创建时间

    Updata_time

    Data_time

    更新时间

    2、创建表脚本

    1. -- 创建树表
    2. create table treenodes(
    3. id INTEGER primary key autoincrement,
    4. tree_note  CHAR(200) not null,
    5. parent_id  INT,
    6. is_delete  INT default 0,
    7. create_time DATETIME not null default current_timestamp,
    8. updata_time DATETIME not null default current_timestamp
    9. )
    10. -- 创建文件内容表
    11. create table articles(
    12. id INTEGER primary key autoincrement,
    13. tree_id INTEGER,
    14. name CHAR(200) not null,
    15. content TEXT,
    16. is_delete INT default 0,
    17. create_time DATETIME not null default current_timestamp,
    18. updata_time DATETIME not null default current_timestamp,
    19. FOREIGN KEY (tree_id)  
    20.   REFERENCES treenodes(id) on delete cascade on update cascade  
    21. )

    3、数据库封装

            1)新增类SqliteIo的类,初始化数据连接,析造数据

            代码如下:

            

    1. class SqliteIo(object):
    2.     def __init__(self):
    3.         '''
    4.         构造函数
    5.         初始化数据库连接
    6.         '''
    7.         self.conn = sqlite3.connect(nbpath)
    8.         self.cur = self.conn.cursor()
    9.     def __del__(self):
    10.         '''
    11.         析造函数
    12.         关闭游标与数据库连接
    13.         :return:
    14.         '''
    15.         self.cur.close()
    16.         self.conn.close()

            2)treenotes增删改查

            代码如下:   

            

    1. def get_treeNode_lst(self):
    2. '''
    3. 获取treenodes所有未删除的数据
    4. :return:
    5. list: [{},{},{}]表数据列表
    6. '''
    7. try:
    8. #执行sql
    9. sql = 'select * from treenodes where is_delete = 0'
    10. self.cur.execute(sql)
    11. #用推导式 获取表头字段名
    12. title = tuple(item[0] for item in self.cur.description)
    13. #获取所有的数据
    14. rows = self.cur.fetchall()
    15. #用推导式 将表头与数据拼装成一个字典列表
    16. result = [dict(zip(title, item)) for item in rows]
    17. return result
    18. except Exception as e:
    19. return []
    20. def insert_treeNode_data(self, data):
    21. '''
    22. 新增节点
    23. :param data: 节点数据
    24. :return: bool 成功与否
    25. '''
    26. try:
    27. sql = '''insert into treenodes(tree_note, parent_id, level) values('{}', {}, {})'''.format(data['tree_node'], data['parent_id'], data['level'])
    28. self.cur.execute(sql)
    29. self.conn.commit()
    30. id = self.cur.lastrowid
    31. return True, id
    32. except Exception as e:
    33. return False
    34. def del_treeNode_data(self, id):
    35. '''
    36. 删除节点(逻辑删)
    37. :param id: 节点id
    38. :return: bool 成功与否
    39. '''
    40. try:
    41. sql = 'update treenodes set is_delete = 1 where id = {}'.format(str(id))
    42. self.cur.execute(sql)
    43. self.conn.commit()
    44. return True
    45. except:
    46. return False
    47. def update_treeNode_data(self, data):
    48. '''
    49. 更新节点名称
    50. :param data: 节点数据 dict
    51. :return: bool 成功与否
    52. '''
    53. try:
    54. sql = '''update treenodes set tree_note = '{}' where id = {}'''.format(data['tree_node'], data['id'])
    55. self.cur.execute(sql)
    56. self.conn.commit()
    57. return True
    58. except:
    59. return False

            3)articles增删改查

              

    1. def get_articles(self, tree_node_id):
    2. '''
    3. 通过树id找文章
    4. :param tree_node_id: 树id
    5. :return: dict,返回文章内容
    6. '''
    7. try:
    8. sql = '''select * from articles where tree_id = {}'''.format(tree_node_id)
    9. # 用推导式 获取表头字段名
    10. self.cur.execute(sql)
    11. title = (item[0] for item in self.cur.description)
    12. #获取数据
    13. item = self.cur.fetchone()
    14. return dict(zip(title, item))
    15. except:
    16. return {}
    17. def insert_articles(self, data):
    18. '''
    19. 新增文章
    20. :param data: 文章数据
    21. :return: bool 成功与否
    22. '''
    23. try:
    24. sql = '''insert into articles(tree_id, name) values({}, '{}')'''.format(data['tree_id'], data['name'])
    25. self.cur.execute(sql)
    26. self.conn.commit()
    27. return True
    28. except:
    29. return False
    30. def updata_articles(self, data):
    31. '''
    32. 更新文章
    33. :param data:
    34. :return: bool 成功与否
    35. '''
    36. try:
    37. sql = '''update articles set name='{}', content='{}' where id = {}'''.format(data['name'], data['content'], data['id'])
    38. self.cur.execute(sql)
    39. self.conn.commit()
    40. return True
    41. except:
    42. return False
    43. def del_articles(self, id):
    44. '''
    45. 删除文章(逻辑删除)
    46. :param id: 文章id
    47. :return: bool 成功与否
    48. '''
    49. try:
    50. sql = '''update articles set is_delete = 1 where id = {}'''.format(str(id))
    51. self.cur.execute(sql)
    52. self.conn.commit()
    53. return True
    54. except:
    55. return False
    56. sqlt = SqliteIo()

    数据库代码封闭完毕,中间的细节,慢慢会补上

    后面的sqlt是将数据库读取类单例化

    四、展示数据

    1、在数据库添加数据

    添加四个树节点,根目录,两个日期(二级)目录,一个文章(三级目录)目录

            

     parent_id决定父节点,id与parent_id构成树节点的级联关系

    添加一篇文章,对tree_id=4

     tree_id,表示这篇文章属于哪个树节点,后期效果,点击某个三级节点,展示对应文章内容

    2、展示树节点

    首先呢,在newWindow.py里导入sqlt数据库操作对象

    编写一个list_to_tree的递归函数,实现数据格式化

    树节点格式

    [

            {

                    Id:1,

                    ....

                    Children:[{子节点}]

            }

    ]

    在NewWindow里添加一个方法get_tree_node(),用例sqlt调用函数get_treeNode_lst()获取数据库里的数据,然后调用list_to_tree()函数将获取的数据转换成树格式

    在构造函数里新增一个m_tree的变量,调用get_tree_node函数,将返回赋值给m_tree

    将树展示在窗体中

    编写函数set_tree(),在其中递归将节点设置到self.my_nodetree中(my_nodetree是窗体树的对象)

    在构造函数init中调用set_tree(),传入self.m_tree,将m_tree的树数据展示出来

    运行runMain.py文件

    窗体中的树展示的节点是按照treenodes里的数据逻辑形成的,‘2022-9-6’、‘2022-9-7’两个节点的parent_id是1,也就是‘根目录’,‘那年夏天’的parent_id是2,也就是‘2022-9-6’

    1. 展示文章

    展示文章应该是点击文章标题展示对应文章,从选择的节点中获取data,在data找到id,通过id在articles的tree_id中找到文章,展示在编辑框中

    (1)切换树节点响应事件函数实现

    在wxF中选择m_nodetree:wxTreeCtrl添加OnLetfDown的事件,on_change_rticles。

    再将生成的代码复制过来,如果熟悉了,可以局部复制,免得再去修改兼容代码

    在newWindow.py覆盖这个事件函数,编写选择节点的数据打印一下

    运行runMain.py,点击树节点来回切换,看控制台打印

    好,切换树节点功能实现

    3、展示文章

    在响应函数里添加获取文章数据并展示在编辑框中的代码,编辑框的对象是m_textEdit

    运行runMain.py节点,点击‘那年夏天’,可以看到右边的编辑框,可以展示对应的文章内容了

    此时我们在数据里多添加一些文章,看看切换是否有效果

    本章完成,下一章讲述树节点数据的增改删的开发

    本章代码:

    https://download.csdn.net/download/weixin_40331132/86616745

  • 相关阅读:
    人工智能(Python)逻辑编程
    最后的防线:数据存储加密方案
    java之Number与Math及Random类
    芯海转债,恒逸转2上市价格预测
    2022年Q2全国网络零售发展指数同比增长3.3%
    充分利用自动化测试的 10 个最佳实践
    高校教务系统登录页面JS分析——四川大学
    消息中间件-RocketMQ(基础、实战、源码、原理看这一篇就够了)
    FWT小结
    泛型的类型擦除后,fastjson反序列化时如何还原?
  • 原文地址:https://blog.csdn.net/weixin_40331132/article/details/126922768