
Итак в Qt 4.8.1 функционал класса QSqlRelationalTableModel нас не устраивает, точнее нам нужен другой, на наш взгляд более удобный.
Почему QSqlRelationalTableModel не подходит см.setRelation.
Что делать?
А сделать можно оказывается следующее:
Примечание: на самом деле как оказалось впоследствие необязательно форкать исходники Qt, так как всего можно добиться стандартным наследованием открытых классов, смотрите Развитие Qt Sql.
Но тем нк менее сама идея изменять исходники, а точнее развивать их вполне правиная.
Сделаем своего наследника класса QSqlTableModel, но в составе исходников Qt.
Унаследуем также приватный класс QSqlTableModelPrivate, все в стиле самого QSqlTableModel, который наследуется от QSqlQueryModel.
Подумав немного мы решили назвать класс PblSqlRelationalTabelModel, так как мы же не разработчики из компании Qt и префикс Q не для нас, у нас будет префикс Pbl.
Мы хотим, чтобы в нашем классе поле id внешней связи было всегда под рукой.
То есть setRelation также будет настраивать связь с внешней таблицей, но дополнительно, кроме текстовой замены, мы будем иметь поле id внешней связи в запросе. Наконец-то решим этот старый вопрос.
Заодно добавим функцию setCalcField для получение sum, count и т.д. по данным полей из других таблиц.
И добавим вообще говоря все , что придет нам в голову.
А что так можно было? Давайте разберемся не бредим ли мы.
Пока проверять будем для SQLite, Qt 4.8.1, под Windows 10.
Основная идея в том, что надо переопределить метод selectStatement класса QSqlTableModel.

Но сначала надо обратить внимание на setTable. Тут всегда сначала очищаются все данные от предыдущих запросов, все данные от других таблиц и т.д.
Сначала setTable делает запрос к базе данных, считывает данные по полям запрашиваемой таблицы и сохраняет их в параметре baseRec приватного класса.
Это оригинальные поля (будем так их называть). Мы же в нашем классе наследнике реализуем дополнительно расширенные поля, где и бедем собирать необходимую информацию по данным их других таблиц.
Внешние связи мы как обычно устанавливаем через стандартную функцию setRelation для полей, для которых есть внешние связи.
И реализуем свою функцию setCalcField для полей вычислений sum, count и т.д. по колонкам других таблиц, связанных с нашей таблицей.
Далее делаем select в модели данных, который вызывает переопределенный нами selectStatement (в нашем классе PblSqlRelationalTabelModel).
В итоге получается, что мы подменяем selectStatement, а точнее формированиие строки sql запроса на свой вариант, где добавляем в запросе получение дополнительных полей.
Конечно после выполнения измененного запроса состав полей может и скорее всего получится другой, то есть отличный от baseRec (добавятся еще поля).
Но самое приятное, что модель данных в Qt будет работать нормально в новых условиях.
QModelIndex-ы будут строится и для новых расширенных полей также как для оригинальных, так как это все есть "таблица", то есть select возвращает таблицу, где есть только колонки и строки.
Мы добавляем функцию setCalcFunc, чтобы вычислять итоговые суммы по колонкам других таблиц, у которых есть связь с нашей таблицей.
Мы создаем наш класс в стиле бинарной совместимости (как в Qt в основном все и реализовано). То есть наши setRelation и setCalcFunc будут хранить настройки где-то в приватном классе доступа к которому снаружи не будет (PblSqlRelationalTableModelPrivate).
Хотя надо отметить, что при сборке статически проекта беспокоится о бинарной совместимости не приходится. Можно почитать здесь:
Настраиваем статику и динамику.
Самое важное, что наш класс PblSqlRelationalTabelModel не нарушает совместимость библиотек Qt, так как мы не изменяем исходники Qt ни в одном месте, а только добавляем новое развитие.
Небольшой визуальный пример, как это может выглядеть :

Это фрагмент программы, которую мы пишем для владельцев контрольно-кассовой техники БИТ драйвер ККТ.
Надо сказать, что ещё всё-таки надо развить класс QSqlRecord, чтобы из функции record(int row) мы получали не просто набор полей/значений строки таблицы из базы данных, но и информацию по relation полям, а именно в каких спец. полях находятся их значения id связей. fork QSqlRecord.
Фильтрация
Фильтрация работает штатно через функцию setFilter. Тут вы уже сами формируете строку фильтра и в общем-то для фильтра по расширенным полям, а именно по вычисляемые полям, все делается единообразно как и для оригинальных полей.
Сортировка
Сортировка или упорядочивание по полю работает штатно, то есть сортируется все без проблем. Весь функционал сортировки реализован в родительских классах.
Нам надо только переопределить сортировку по расширенным полям. Это делается в функции orderClause.