从 SQLite 数据库中检索日期 (INTEGER) 并将其插入到 QDateEdit 字段
Retrieve date (INTEGER) from SQLite database and insert it to QDateEdit field
我有一个包含 2 个字段的简单测试表单:姓名、出生日期。它们都从底层的 SQLite 数据库中获取值。数据库中的生日字段是 INTEGER(UNIX 时间)类型。我可以得到表格上的名字,但是我不能得到生日(我得到的是 1/1/2000)。我怀疑我的问题与从 INTEGER 到 QDate 的类型转换有关,但我不知道如何解决它。
下面是这个简化版的代码。我已经包含了重新创建问题的最低限度。如果您将此代码作为 .py 文件保存在一个目录中,并从那里 运行 它,它将在该目录中创建数据库并显示表单。我正在使用视图/模型方法,如果任何答案可以在现有代码中工作,我们将不胜感激。
非常感谢
import sys
import os.path
import sqlite3
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
from PyQt5 import QtSql as qts
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
DB_NAME = 'test.db'
target_db = os.path.join(DIR_PATH, DB_NAME)
# create database 'test.db', add schema, then close it
cnn = sqlite3.connect(target_db)
c = cnn.cursor()
c.executescript("""
DROP TABLE IF EXISTS clients;
CREATE TABLE clients
(
id INTEGER PRIMARY KEY,
name STRING,
birthdate INTEGER
);
INSERT INTO clients VALUES (1, 'Error Flynn', '12/30/1980');
""")
cnn.commit()
cnn.close()
class Model(qtc.QObject):
connection_error = qtc.pyqtSignal(str)
def start_db(self):
connection_error = ''
# create a db connection:
self.db = qts.QSqlDatabase.addDatabase('QSQLITE')
self.db.setDatabaseName(target_db)
# test the connection for errors:
if not self.db.open():
connection_error = f'{self.db.lastError().text()}'
sys.exit(1)
if connection_error:
self.error.emit(connection_error)
def create_model(self):
self.clients_model = qts.QSqlRelationalTableModel()
self.clients_model.setTable('clients')
# query once the model to populate it
self.clients_model.select()
return self.clients_model
# create the Clients Form
class View(qtw.QWidget):
error = qtc.pyqtSignal(str)
def __init__(self, a_clients_model):
super().__init__()
self.setLayout(qtw.QFormLayout())
# The 2 Client Fields
self.client_name = qtw.QLineEdit()
self.layout().addRow('Name: ', self.client_name)
self.client_bdate = qtw.QDateEdit()
self.layout().addRow('Birthdate: ', self.client_bdate)
self.client_bdate.setCalendarPopup(True)
# create a mapper and point it to the clients_model
self.this_clients_model = a_clients_model
self.mapper = qtw.QDataWidgetMapper(self)
self.mapper.setModel(self.this_clients_model)
self.mapper.setItemDelegate(
qts.QSqlRelationalDelegate(self))
# map the Client Name field
self.mapper.addMapping(
self.client_name,
self.this_clients_model.fieldIndex('name')
)
# map the Client Birthdate field
self.mapper.addMapping(
self.client_bdate,
self.this_clients_model.fieldIndex('birthdate')
# client_birthdate is declared INTEGER in the SQLite database,
# to be converted to a QDateEdit object before it can be used!
)
# this will show the first record in the tbl_clients
self.mapper.setCurrentIndex(0)
self.show()
# display error message originating in Model class
def show_connection_error(self, error):
qtw.QMessageBox.critical(
None,
'DB Connection Error',
'Could not open database file: '
f'{error}')
sys.exit(1)
class MainWindow(qtw.QMainWindow):
def __init__(self):
"""MainWindow constructor.
"""
super().__init__()
# Main UI code goes here
self.stack = qtw.QStackedWidget()
self.setCentralWidget(self.stack)
self.model = Model()
self.model.start_db()
self.view = View(self.model.create_model())
self.stack.addWidget(self.view)
self.model.connection_error.connect(self.view.show_connection_error)
# End main UI code
self.show()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
# it's required to save a reference to MainWindow.
# if it goes out of scope, it will be destroyed.
mw = MainWindow()
sys.exit(app.exec())
问题是字符串“12/30/1980”和默认 QDate 之间没有转换。这种情况下的解决方案是使用委托来进行该转换。另一方面,我认为没有必要使用 QSqlRelationalDelegate 作为委托。
class Delegate(qtw.QItemDelegate):
def setEditorData(self, editor, index):
if isinstance(editor, qtw.QDateEdit):
dt = qtc.QDate.fromString(index.data(), "MM/dd/yyyy")
editor.setDate(dt)
else:
super().setEditorData(editor, index)
def setModelData(self, editor, model, index):
if isinstance(editor, qtw.QDateEdit):
data = editor.date().toString("MM/dd/yyyy")
model.setData(index, data)
else:
super().setModelData(editor, model, index)
# create a mapper and point it to the clients_model
self.this_clients_model = a_clients_model
self.mapper = qtw.QDataWidgetMapper(self)
self.mapper.setModel(self.this_clients_model)
<b># self.mapper.setItemDelegate(qts.QSqlRelationalDelegate(self))
self.mapper.setItemDelegate(Delegate(self))</b>
我有一个包含 2 个字段的简单测试表单:姓名、出生日期。它们都从底层的 SQLite 数据库中获取值。数据库中的生日字段是 INTEGER(UNIX 时间)类型。我可以得到表格上的名字,但是我不能得到生日(我得到的是 1/1/2000)。我怀疑我的问题与从 INTEGER 到 QDate 的类型转换有关,但我不知道如何解决它。
下面是这个简化版的代码。我已经包含了重新创建问题的最低限度。如果您将此代码作为 .py 文件保存在一个目录中,并从那里 运行 它,它将在该目录中创建数据库并显示表单。我正在使用视图/模型方法,如果任何答案可以在现有代码中工作,我们将不胜感激。
非常感谢
import sys
import os.path
import sqlite3
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
from PyQt5 import QtSql as qts
DIR_PATH = os.path.dirname(os.path.abspath(__file__))
DB_NAME = 'test.db'
target_db = os.path.join(DIR_PATH, DB_NAME)
# create database 'test.db', add schema, then close it
cnn = sqlite3.connect(target_db)
c = cnn.cursor()
c.executescript("""
DROP TABLE IF EXISTS clients;
CREATE TABLE clients
(
id INTEGER PRIMARY KEY,
name STRING,
birthdate INTEGER
);
INSERT INTO clients VALUES (1, 'Error Flynn', '12/30/1980');
""")
cnn.commit()
cnn.close()
class Model(qtc.QObject):
connection_error = qtc.pyqtSignal(str)
def start_db(self):
connection_error = ''
# create a db connection:
self.db = qts.QSqlDatabase.addDatabase('QSQLITE')
self.db.setDatabaseName(target_db)
# test the connection for errors:
if not self.db.open():
connection_error = f'{self.db.lastError().text()}'
sys.exit(1)
if connection_error:
self.error.emit(connection_error)
def create_model(self):
self.clients_model = qts.QSqlRelationalTableModel()
self.clients_model.setTable('clients')
# query once the model to populate it
self.clients_model.select()
return self.clients_model
# create the Clients Form
class View(qtw.QWidget):
error = qtc.pyqtSignal(str)
def __init__(self, a_clients_model):
super().__init__()
self.setLayout(qtw.QFormLayout())
# The 2 Client Fields
self.client_name = qtw.QLineEdit()
self.layout().addRow('Name: ', self.client_name)
self.client_bdate = qtw.QDateEdit()
self.layout().addRow('Birthdate: ', self.client_bdate)
self.client_bdate.setCalendarPopup(True)
# create a mapper and point it to the clients_model
self.this_clients_model = a_clients_model
self.mapper = qtw.QDataWidgetMapper(self)
self.mapper.setModel(self.this_clients_model)
self.mapper.setItemDelegate(
qts.QSqlRelationalDelegate(self))
# map the Client Name field
self.mapper.addMapping(
self.client_name,
self.this_clients_model.fieldIndex('name')
)
# map the Client Birthdate field
self.mapper.addMapping(
self.client_bdate,
self.this_clients_model.fieldIndex('birthdate')
# client_birthdate is declared INTEGER in the SQLite database,
# to be converted to a QDateEdit object before it can be used!
)
# this will show the first record in the tbl_clients
self.mapper.setCurrentIndex(0)
self.show()
# display error message originating in Model class
def show_connection_error(self, error):
qtw.QMessageBox.critical(
None,
'DB Connection Error',
'Could not open database file: '
f'{error}')
sys.exit(1)
class MainWindow(qtw.QMainWindow):
def __init__(self):
"""MainWindow constructor.
"""
super().__init__()
# Main UI code goes here
self.stack = qtw.QStackedWidget()
self.setCentralWidget(self.stack)
self.model = Model()
self.model.start_db()
self.view = View(self.model.create_model())
self.stack.addWidget(self.view)
self.model.connection_error.connect(self.view.show_connection_error)
# End main UI code
self.show()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
# it's required to save a reference to MainWindow.
# if it goes out of scope, it will be destroyed.
mw = MainWindow()
sys.exit(app.exec())
问题是字符串“12/30/1980”和默认 QDate 之间没有转换。这种情况下的解决方案是使用委托来进行该转换。另一方面,我认为没有必要使用 QSqlRelationalDelegate 作为委托。
class Delegate(qtw.QItemDelegate):
def setEditorData(self, editor, index):
if isinstance(editor, qtw.QDateEdit):
dt = qtc.QDate.fromString(index.data(), "MM/dd/yyyy")
editor.setDate(dt)
else:
super().setEditorData(editor, index)
def setModelData(self, editor, model, index):
if isinstance(editor, qtw.QDateEdit):
data = editor.date().toString("MM/dd/yyyy")
model.setData(index, data)
else:
super().setModelData(editor, model, index)
# create a mapper and point it to the clients_model
self.this_clients_model = a_clients_model
self.mapper = qtw.QDataWidgetMapper(self)
self.mapper.setModel(self.this_clients_model)
<b># self.mapper.setItemDelegate(qts.QSqlRelationalDelegate(self))
self.mapper.setItemDelegate(Delegate(self))</b>