如何基于姓名两列实现数据库表的Qt实时搜索功能
多列搜索实现方案
方案一:SQL层面过滤(推荐,大数据量更高效)
直接在SQL语句中同时匹配firstname和surname列,从数据库层面筛选符合条件的记录,减少客户端处理的数据量,性能更优。
修改后代码示例
def on_search_text_changed(text): # 参数化查询避免SQL注入风险 search_method = ''' SELECT id_no, firstname, surname FROM name_list WHERE firstname LIKE ? OR surname LIKE ? ''' # 构造模糊匹配参数,支持任意位置的字符匹配 search_param = f'%{text}%' sql_search_method = cur.execute(search_method, (search_param, search_param)).fetchall() # 清空模型并重新填充数据 model.clear() model.setHorizontalHeaderLabels(['Id_no','First Name','Surname']) for row_idx, (id_no, firstname, surname) in enumerate(sql_search_method): model.setItem(row_idx, 0, QStandardItem(id_no)) model.setItem(row_idx, 1, QStandardItem(firstname)) model.setItem(row_idx, 2, QStandardItem(surname)) # 绑定搜索框文本变化信号 self.ui.lineEdit.textChanged.connect(on_search_text_changed) # 表格样式初始化 self.ui.tableView.setStyleSheet('font-size: 12px;') self.ui.tableView.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) self.ui.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.ui.tableView.setModel(model)
关键说明
- 必须使用参数化查询(
?占位符),避免SQL注入安全问题 LIKE '%{text}%'实现模糊匹配,输入字符出现在姓名任意位置都能命中- 每次搜索文本变化时重新查询数据库,保证数据实时准确
方案二:Qt代理模型层面多列过滤
如果数据量较小,不想频繁请求数据库,可以先加载全量数据,通过自定义代理模型实现多列过滤。
自定义代理模型代码
from PyQt5.QtCore import QSortFilterProxyModel class MultiColumnFilterProxyModel(QSortFilterProxyModel): def filterAcceptsRow(self, source_row, source_parent): pattern = self.filterRegExp() if pattern.isEmpty(): return True source_model = self.sourceModel() # 检查第1列(First Name)和第2列(Surname) for col in [1, 2]: index = source_model.index(source_row, col, source_parent) data = source_model.data(index) if pattern.indexIn(data) != -1: return True return False # 初始化全量数据模型 search_method = ''' SELECT id_no,firstname,surname FROM name_list''' sql_search_method = cur.execute(search_method).fetchall() model = QStandardItemModel(len(sql_search_method), 3) model.setHorizontalHeaderLabels(['Id_no','First Name','Surname']) for row_idx, (id_no, firstname, surname) in enumerate(sql_search_method): model.setItem(row_idx, 0, QStandardItem(id_no)) model.setItem(row_idx, 1, QStandardItem(firstname)) model.setItem(row_idx, 2, QStandardItem(surname)) # 使用自定义多列过滤代理 filter_proxy_model = MultiColumnFilterProxyModel() filter_proxy_model.setSourceModel(model) filter_proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive) self.ui.lineEdit.textChanged.connect(filter_proxy_model.setFilterRegExp) # 表格样式设置 self.ui.tableView.setStyleSheet('font-size: 12px;') self.ui.tableView.verticalHeader().setSectionResizeMode(QHeaderView.Stretch) self.ui.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) self.ui.tableView.setModel(filter_proxy_model)
关键说明
- 重写
filterAcceptsRow方法,遍历需要过滤的列,只要任意一列匹配搜索文本就保留该行 - 适合数据量不大的场景,避免频繁数据库请求
原代码问题修正
你原来的代码存在两处关键错误:
model = QStandardItemModel(len(sql_search_method), 1)列数设为1,但实际有3列数据,需改为3- 循环赋值时
model.setItem(row, 1, item)只往第1列填充数据,导致其他列为空,需按对应列索引分别赋值
内容的提问来源于stack exchange,提问作者Kobby
相关产品推荐
相关产品推荐

