insertRows и ее вариация insertRow относятся к вставке строки в модель данных (не путайте с базой данных).
Процесс вставки новой строки в модель данных заслуживает особого внимания. Например если первый раз вставить строку и далее никаких полей этой строки не изменять увидим примерно такое:

И это вроде бы нормально все выглядит, строка добавилась снизу правильно.
Но вот второй раз попытка добавить строку приводит уже к неправильным результатам:

Во-первых обратите внимание, что стратегия редактирования у нас выбрана OnFieldChange.
Во-вторых id поля двух добавленных снизу строк пустые, то есть submit/select не происходит. И это явно нарушает логику стратегии модели данных. Но как так получается?
Дело в том, что пока вы не установите хотя бы одному полю строки какое-то значение,то в editBuffer соответственно не появится флага generated yes ни у какого-поля. И это значит при submit эта строка по просту не будет вставлена в базу данных. А вот в модели данных она останется.
А как такое может быть? Кстати это касается для всех стратегий модели данных и OnRowChange и OnManualSubmit (не важно).
Сразу можно сказать, что лечится это просто обработкой сигнала primeInsert (там по ссылке передается указатель на editBuffer) и установкой любому полю editBuffer флага genereted = yes (а значение можно и не устанавливать).
Вот код вызова QSqlTableModel::insertRows:
bool QSqlTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
Q_D(QSqlTableModel);
if (row < 0 || count <= 0 || row > rowCount() || parent.isValid())
return false;
switch (d->strategy) {
case OnFieldChange:
case OnRowChange:
if (count != 1)
return false;
beginInsertRows(parent, row, row);
d->insertIndex = row;
// ### apply dangling changes...
d->clearEditBuffer();
emit primeInsert(row, d->editBuffer);
break;
case OnManualSubmit:
beginInsertRows(parent, row, row count - 1);
if (!d->cache.isEmpty()) {
QMap::Iterator it = d->cache.end();
while (it != d->cache.begin() && (--it).key() >= row) {
int oldKey = it.key();
const QSqlTableModelPrivate::ModifiedRow oldValue = it.value();
d->cache.erase(it);
it = d->cache.insert(oldKey count, oldValue);
}
}
for (int i = 0; i < count; i) {
d->cache[row i] = QSqlTableModelPrivate::ModifiedRow(QSqlTableModelPrivate::Insert,
d->rec);
emit primeInsert(row i, d->cache[row i].rec);
}
break;
}
endInsertRows();
return true;
}
Для стратегии OnFieldChange и OnRowChange сначала вызывается beginInsertRows(parent, row, row) базового абстрактного класса QAbstractItemModel и в конце вызывается endInsertRows(). Зачем?
void QAbstractItemModel::beginInsertRows(const QModelIndex &parent, int first, int last)
{
Q_ASSERT(first >= 0);
Q_ASSERT(last >= first);
Q_D(QAbstractItemModel);
d->changes.push(QAbstractItemModelPrivate::Change(parent, first, last));
emit rowsAboutToBeInserted(parent, first, last);
d->rowsAboutToBeInserted(parent, first, last);
}