0

I'm using a QTableView along with a superclassed QSqlTableModel to display a sqlite table into Qt and inserting new records dropping a csv file.

I have followed the doc and came up with the example reported below. I have recreated a very light reproducible example to show what is happening to my code, no sanity check or quality code has been intentionally used. It's tested against PySide6

import sys

from qtpy.QtWidgets import QApplication, QTableView, QWidget
from qtpy.QtCore import QModelIndex, QMimeData, Qt
from qtpy.QtSql import QSqlDatabase, QSqlTableModel, QSqlQuery
from pandas import read_csv

def create_table():
    # Dummy very simple table
    _query_str = """CREATE TABLE MyTable ( 
    ID     INTEGER PRIMARY KEY AUTOINCREMENT,
    Field1 INTEGER,
    Field2 TEXT);"""

    query = QSqlQuery(db=db, query=_query_str)
    query.exec_()

class MyTableModel(QSqlTableModel):

    def __init__(self, table_name, db):
        QSqlTableModel.__init__(self, db=db)
        self.setTable(table_name)

    def canDropMimeData(self, data: QMimeData, action: Qt.DropAction, row: int, column: int, parent: QModelIndex) -> bool:
        return True # <-- Just for the example

    def supportedDropActions(self) -> Qt.DropAction:
        return Qt.DropAction.CopyAction | Qt.DropAction.MoveAction | Qt.DropAction.LinkAction

    def dropMimeData(self, data: QMimeData, action: Qt.DropAction, row: int, column: int, parent: QModelIndex) -> bool:
        csv_filename = data.urls()[0].toLocalFile()
        df = read_csv(csv_filename, delimiter=',', header=0)

        for _, row in df.iterrows():
            record = self.record()
            record.remove(0) # <-- Remove the ID field
            record.setValue('Field1', row['Field1'].values[0])
            record.setValue('Field2', row['Field2'].values[0])
            self.insertRecord(-1, record)


if __name__ == '__main__':
    # In memory database just for the purpose of the example
    db = QSqlDatabase.addDatabase("QSQLITE", ":memory:")
    db.open()
    if not db.open():
        raise "Database not opened"
    create_table()
    app = QApplication([])
    table = QTableView()
    model = MyTableModel('MyTable', db)
    table.setModel(model)
    table.setAcceptDrops(True)
    table.show()

    sys.exit(app.exec_())

What I get is that canDropMimeData and supportedDropActions are correctly called, but (using debug) dropMimeData is never called

And the below image shows that, even if canDropMimeData returns True, the file seems not to be accepted.

enter image description here

Edit 1 - QSqlTableModel issue

I found out that the problem is with QSqlTableModel. If I use a bare QStandardItemModel, everything works fine. Any work-around?

Buzz
  • 1,102
  • 1
  • 9
  • 24

1 Answers1

1

By default, item models don't provide drag and drop support.

In order to properly allow that, many aspects have to be checked, including that the flags() returned by any index that would accept drop must also have the Qt.ItemIsDropEnabled.

If you want to allow that only for the model (drop on an empty area, not on items), that index would be the root index, aka, an invalid index:

    def flags(self, index):
        flags = super().flags(index)
        if not index.isValid():
            flags |= Qt.ItemIsDropEnabled
        return flags
musicamante
  • 41,230
  • 6
  • 33
  • 58
  • I was missing that piece of information. Thank you. I should infer that QStandardItemModel implement that flag, am I wrong? – Buzz Feb 17 '23 at 17:26
  • Anyway, I was not able to find this info inside the Model/View Framework documentation. Before I submit an issue with the doc, have you got any ref? – Buzz Feb 17 '23 at 17:27
  • It's explained in the model view programming guide related to [subclassing and drag&drop](https://doc.qt.io/qt-6/model-view-programming.html#enabling-drag-and-drop-for-items). I strongly suggest you to take your time to read that (don't make the same mistake I did years ago, when I saw the length of that document and decided it was too much...) – musicamante Feb 17 '23 at 17:38
  • Great, I missed that paragraph while reading the rest! Thank you again – Buzz Feb 17 '23 at 20:48