Python 从SQLite数据库中检索日期(整数),并将其插入QDateEdit字段

Python 从SQLite数据库中检索日期(整数),并将其插入QDateEdit字段,python,pyqt,pyqt5,Python,Pyqt,Pyqt5,我有一个简单的测试表单,有两个字段:姓名、生日。它们都从底层SQLite数据库获取值。数据库中的生日字段的类型为整数(UNIX时间)。我可以在表格上记下名字,但我不能记下生日(我只能记下2000年1月1日)。我怀疑我的问题与从INTEGER到QDate的类型转换有关,但我不知道如何解决它 下面是这个简化版本的代码。我已经包含了重现问题的最小值。如果将此代码保存在目录中作为.py文件并从那里运行,它将在该目录中创建数据库并显示表单。我使用的是视图/模型方法,如果能够在现有代码范围内工作,我将特别感

我有一个简单的测试表单,有两个字段:姓名、生日。它们都从底层SQLite数据库获取值。数据库中的生日字段的类型为整数(UNIX时间)。我可以在表格上记下名字,但我不能记下生日(我只能记下2000年1月1日)。我怀疑我的问题与从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)
#创建映射器并将其指向客户机#
self.this\u clients\u model=a\u clients\u model
self.mapper=qtw.QDataWidgetMapper(self)
self.mapper.setModel(self.this\u clients\u model)
#self.mapper.setItemDelegate(qts.QSqlRelationalDelegate(self))

self.mapper.setItemDelegate(Delegate(self))
谢谢你,eyllanesc,它工作起来很有魅力!我仍然需要找出为什么它不能在我的实际应用程序上工作,但是,您认为我的“客户”表引用许多其他查找表会有什么不同吗?在这种情况下是否需要QSqlRelationalDelegate?@ErrorFlynn尝试将
类委托(qtw.QItemDelegate):
更改为
类委托(qts.QSqlRelationalDelegate):
再次感谢更新。因为我对这个很陌生,我不明白其中的逻辑。委托有两个方法setEditorData,用于格式化从数据库检索到的日期,以供QDateEdit使用。setModelData将数据库使用的QDateEdit(日历)中的用户输入格式化。但是,对于onDateChanged事件或类似事件,我们不需要显式地调用这些方法来工作吗?此外,在更新代码的示例中,当我尝试使用日历更改日期时,更改不会写入数据库。我遗漏了什么?@ErrorFlynn您的问题是由模型引起的,因为默认情况下它不会将信息保存在数据库中,因此您必须添加
self.clients\u model.setEditStrategy(qts.QSqlTableModel.onfeldchange)
# 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))
self.mapper.setItemDelegate(Delegate(self))