Как преобразовать строку в формат даты в QDataWidgetMapper?

Ниже приведен пример кода:

import sys
from PyQt5 import QtCore, QtWidgets, QtSql, uic


class FilterProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._filter_value = None

    @property
    def filter_value(self):
        return self._filter_value

    @filter_value.setter
    def filter_value(self, value):
        self._filter_value = value
        self.invalidateFilter()

    def filterAcceptsRow(self, sourceRow, sourceParent):
        if self.filter_value is None:
            return super().filterAcceptsRow(sourceRow, sourceParent)
        if self.filterKeyColumn() >= 0:
            value = (
                self.sourceModel()
                .index(sourceRow, self.filterKeyColumn(), sourceParent)
                .data(self.filterRole())
            )
            return value == self.filter_value

        for column in range(self.columnCount()):
            value = (
                self.sourceModel()
                .index(sourceRow, column, sourceParent)
                .data(self.filterRole())
            )
            if value == self.filter_value:
                return True
        return False

    def setFilterRegExp(self, filter):
        self.filter_value = None
        super().setFilterRegExp(filter)


class UI(QtWidgets.QMainWindow):
    def __init__(self):
        super(UI, self).__init__()
        uic.loadUi("tableview.ui", self)
        self.tableView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)

        db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
        db.setDatabaseName("book.db")
        db.open()

        self.model = QtSql.QSqlTableModel(self)
        self.model.setTable("card")
        self.model.select()

        self.proxy = FilterProxyModel(self)
        self.proxy.setSourceModel(self.model)

        self.tableView.setModel(self.proxy)
        self.model.select()

        self.edit.clicked.connect(self.edit_items)
        self.refresh.clicked.connect(self.refresh_table)

        r = self.model.record()
        column_names = [r.field(i).name().title() for i in range(r.count())]

        self.comboBox.addItems([x for x in column_names])

        self.horizontalHeader = self.tableView.horizontalHeader()
        self.horizontalHeader.sectionClicked.connect(
            self.tableView_horizontalHeader_sectionClicked
            )
        self.lineEdit.textChanged.connect(self.lineEdit_textChanged)

    def tableView_horizontalHeader_sectionClicked(self, logicalIndex):
        menu = QtWidgets.QMenu(self)

        values = []

        for row in range(self.model.rowCount()):
            value = self.model.index(row, logicalIndex).data(self.proxy.filterRole())
            values.append(value)

        action_all = QtWidgets.QAction("All", self)
        action_all.setData(None)
        menu.addAction(action_all)
        menu.addSeparator()

        for value in sorted(list(set(values))):
            action = QtWidgets.QAction(str(value), self)
            action.setData(value)
            menu.addAction(action)

        headerPos = self.tableView.mapToGlobal(self.horizontalHeader.pos())
        posY = headerPos.y() + self.horizontalHeader.height()
        posX = headerPos.x() + self.horizontalHeader.sectionPosition(logicalIndex)

        action = menu.exec_(QtCore.QPoint(posX, posY))

        if action is not None:
            self.proxy.setFilterKeyColumn(logicalIndex)
            self.proxy.filter_value = action.data()

    def lineEdit_textChanged(self):
        search = QtCore.QRegExp(
            self.lineEdit.text(), QtCore.Qt.CaseInsensitive, QtCore.QRegExp.RegExp
        )
        self.proxy.setFilterKeyColumn(self.comboBox.currentIndex())
        self.proxy.setFilterRegExp(search)

    def edit_items(self):

        if not self.model.rowCount():
            return
        index = self.tableView.currentIndex()
        if index.isValid():
            row = index.row()
        else:
            row = 0

        name_line = QtWidgets.QLineEdit(readOnly=True)
        age_edit = QtWidgets.QSpinBox()
        gender_combo = QtWidgets.QComboBox()
        genders = "M", "F"
        gender_combo.addItems(genders)

        date_of_birth = QtWidgets.QDateEdit()
        date_of_birth.setDisplayFormat("d-MMM-yyyy")
        
        updateButton = QtWidgets.QPushButton("Update")

        mapper = QtWidgets.QDataWidgetMapper()
        mapper.setSubmitPolicy(QtWidgets.QDataWidgetMapper.ManualSubmit)
        mapper.setModel(self.tableView.model())
        mapper.addMapping(name_line, 0)
        mapper.addMapping(age_edit, 1)
        mapper.addMapping(gender_combo, 2)
        mapper.addMapping(date_of_birth, 3)
        
        mapper.setCurrentIndex(row)

        dialog = QtWidgets.QDialog()
        dialog.setWindowTitle("Edit Window")

        layout = QtWidgets.QVBoxLayout(dialog)

        formLayout = QtWidgets.QFormLayout()
        layout.addLayout(formLayout)
        formLayout.addRow("Name", name_line)
        formLayout.addRow("Age", age_edit)
        formLayout.addRow("Gender", gender_combo)
        formLayout.addRow("Date of Birth", date_of_birth)
        
        layout.addWidget(updateButton)
        updateButton.clicked.connect(dialog.accept)

        if dialog.exec_():
            mapper.submit()

    def refresh_table(self):
        print("refresh")


def main():
    app = QtWidgets.QApplication(sys.argv)
    w = UI()
    w.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

Я пытаюсь редактировать данные строки из Qsqltablemodel, используя QDataWidgetMapper(). Столбец даты находится в текстовом формате в таблице моей базы данных, я хочу использовать формат даты как d-MMM-yyyy. Когда я пытаюсь отредактировать строку, столбец даты устанавливает формат даты по умолчанию как 1-1-2000. Как это сделать? Ниже приведен пример изображения: введите здесь описание изображения


person user3030327    schedule 23.08.2020    source источник
comment
Не могли бы вы объяснить на примере фразу: Столбец даты находится в текстовом формате в таблице моей базы данных, я хочу использовать формат даты как d-MMM-yyyy. Как это сделать? Например, вы можете указать на строку в своей БД   -  person eyllanesc    schedule 23.08.2020
comment
@eyllanesc . Я отредактировал код примера.   -  person user3030327    schedule 23.08.2020
comment
ммм я вас не понимаю. Вы можете поделиться book.db (через диск, дропбокс и т. д.). Также покажите изображение проблемы и другое изображение того, что вы хотите получить.   -  person eyllanesc    schedule 23.08.2020
comment
Я забыл загрузить изображение, только что обновил.   -  person user3030327    schedule 23.08.2020
comment
Отлично, не могли бы вы поделиться БД, например book.db, через диск, Dropbox или другой сервис?   -  person eyllanesc    schedule 23.08.2020
comment
Пожалуйста, найдите ссылку выше, чтобы получить приложение db.   -  person user3030327    schedule 23.08.2020


Ответы (1)


По умолчанию QtSql может обрабатывать строковые столбцы в определенном формате, таком как QDate и QDateTime (как указано в документации sqlite), но в данном случае он не соответствует этим форматам, поэтому Qt не знает, как их интерпретировать, и отображает их как текст. Поэтому вы должны преобразовать этот текст в QDate и наоборот, используя делегат:

class ItemDelegate(QtWidgets.QItemDelegate):
    def setEditorData(self, editor, index):
        if index.column() == 3 and isinstance(editor, QtWidgets.QDateEdit):
            text = index.data()
            date = QtCore.QDate.fromString(text, "d-MMM-yyyy")
            editor.setDate(date)
            return
        super().setEditorData(editor, index)

    def setModelData(self, editor, model, index):
        if index.column() == 3 and isinstance(editor, QtWidgets.QDateEdit):
            text = editor.date().toString("d-MMM-yyyy")
            model.setData(index, text)
            return
        super().setModelData(editor, model, index)
# ...
mapper = QtWidgets.QDataWidgetMapper()
delegate = ItemDelegate(mapper)
mapper.setItemDelegate(delegate)
# ...
person eyllanesc    schedule 23.08.2020