dataChanged

Из обработчика сигнала dataChanged модели данных нельзя вызывать setData

Надо понимать, что dataChanged испускается в модели данных как раз в функции setData  и таким образом вызовы setData получатся вложенными (возникнет рекурсия), а этого лучше избегать.

И хотя испускание dataChanged происходит в самом конце setData все-таки лучше в обработчике dataChanged не использовать setData.

bool QSqlTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    Q_D(QSqlTableModel);
    if (role != Qt::EditRole)
        return QSqlQueryModel::setData(index, value, role);

    if (!index.isValid() || index.column() >= d->rec.count() || index.row() >= rowCount())
        return false;

    bool isOk = true;
    switch (d->strategy) {
    case OnFieldChange: {
        if (index.row() == d->insertIndex)
        {
            // это признак , что мы в режиме вставки новой строки

            QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
            // пока ничего не пишется в базу данных, накапливаем в буфере данные по полям
            return true;
        }

        // значит мы в режиме редактирования строки

        d->clearEditBuffer(); // потому что при OnFieldChange изменение только одного поля пишется в базу, но вдруг еще какие-то поля в буфере установлены (generated yes)
        // также происходит инициализация editBuffer - это важно

        // устанавливаем значение поля   generated=yes
        QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);

        // поскольку только одно поле помечено будет как generated
        // то updateRowInTable только одно поле изменит в базе.
        isOk = updateRowInTable(index.row(), d->editBuffer);

        if (isOk)
            select(); // поскольку у нас OnFieldChange обновляем талицу заново

        emit dataChanged(index, index); // сигнализируем, что поле в базе уже изменено

        break;
    }
    case OnRowChange:
        if (index.row() == d->insertIndex)
        {
            // это признак , что мы в режиме вставки новой строки
            // (несуществующей еще в базе данных строки)

            QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);
            return true;
        }
        if (d->editIndex != index.row())
        {
            // если текущая строка почему-то не в режиме редактирования данной текущей строки

            if (d->editIndex != -1) // но в режиме редактирования почему-то другой строки
                submit(); // то надо записать эту другую строку сначала в базу данных
            d->clearEditBuffer(); // и очистить editBuffer для текущей строки
        }
        qDebug() << "56858637856965 " <editBuffer;

        // устанавливаем значение поля в editBuffer
        QSqlTableModelPrivate::setGeneratedValue(d->editBuffer, index.column(), value);

        // выставляем в editIndex, что мы редактируем это строку
        d->editIndex = index.row();

        emit dataChanged(index, index); // сигнализируем, что поле изменено
        // но еще не записано в базу данных (в отличии от OnFieldChange)
        break;
    case OnManualSubmit:
    {
        // читаем из кеша QMap текущую строку

        QSqlTableModelPrivate::ModifiedRow &row = d->cache[index.row()];

        // тут важно, что если в кеше нет еще такой row
        // то при использовании для доступа через квадратные скобки []
        // новый пустой ModifiedRow будет создан !

        if (row.op == QSqlTableModelPrivate::None)
        {
            // в кеше не было такой row , создали новый элемент ModifiedRow
            row.op = QSqlTableModelPrivate::Update;

            // запоминаем данные всех полей текущей строки в rec
            row.rec = d->rec;

            // на всякий случай очищаем поля для новой строки кеша
            QSqlTableModelPrivate::clearGenerated(row.rec);


            // QSqlRecord primaryValues заполнятеся данными из query
            // QSqlQueryModel::indexInQuery - создает индекс в базе данных, если его нет еще
            // primaryValues тип QSqlRecord, но там только индексные поля содержатся, вот пример:
            // SqlRecord( 1 ) " 0:" QSqlField("id", int, required: no, generated: yes) "39"
            row.primaryValues = d->primaryValues(indexInQuery(index).row());
            //qDebug() << " row.primaryValues " << row.primaryValues;
        }

        // устанавливаем значение поля в row.rec (строка кеша)
        QSqlTableModelPrivate::setGeneratedValue(row.rec, index.column(), value);

        emit dataChanged(index, index); // сигнализируем об изменении поля строки
        // это еще только в кеше, в самой базе данных изменений еще нет
        break;
    }
    }
    return isOk;
}

Может показаться, что отрабатывать изменения поля в одной ячейки строки, чтобы потом изменить значение в другой ячейки строки можно переопределив QAbstractItemView::commitData  (класс представления данных). И это будет правильно с той точки зрения, что первый вызов setData уже закончился и второй вызов setData не прервет первый вызов.