Использование PySide2.QtSql.QSqlRelationalTableModel()
Я решил использовать и изучить собственный класс Qt QtSql. Использование QSqlQuery() очень просто и очень похоже на SqlAlchemy.
Я пробовал использовать подход QTableView/Model, но с очень ограниченным успехом.
Мой справочный документ - это старая книга "Быстрое программирование графического интерфейса с помощью Python и Qt", но ее можно использовать.
После долгих экспериментов мне удалось частично, но моя текущая проблема немного сбивает с толку, и мои текущие поиски в Интернете не помогли (на сегодняшний день)
Форма отображает запрошенную информацию для первых двух записей, но не для последующих записей (последних двух). В базе четыре записи.
Разбивка базы данных
Основная таблица "tblRecipe" содержит ключ, имя рецепта, категорию и описание. Таблица поддержки "tblIngrediants" содержит от одного до нескольких ингредиентов для рецепта: поля: "ингредиент из последней таблицы в таблицу поиска, чтобы изменить целое число категории в "tblRecipe" на удобочитаемый текст. Я еще не пробовал включить эту таблицу.
Вопрос: Почему я получаю правильную информацию для первых 2 записей, а не для последних 2.
Я включил часть кода, имеющую отношение к моей проблеме.
import os
import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtSql import *
from PySide2.QtWidgets import *
import qrc_resources
RECIPEKEY, RECIPENAME, RECIPECATEGORY, RECIPEDESCRIPTION = range(4)
INGREDIANTKEY, INGREDIANTDESCRIPTION, INGREDIANTRECIPEKEY, INGREDIANTQUANTITY = range(4)
class RecipeDlg(QDialog):
FIRST, PREV, NEXT, LAST = range(4)
def __init__(self, parent=None):
super(RecipeDlg, self).__init__(parent)
catLabel = QLabel("Category:")
self.catEdit = QLineEdit()
catLabel.setBuddy(self.catEdit)
nameLabel = QLabel("Name:")
self.nameEdit = QLineEdit()
nameLabel.setBuddy(self.nameEdit)
IngrediantLabel = QLabel("Ingrediants:")
self.tvIngrediants = QTableView()
descriptionLabel = QLabel("Description:")
self.descriptionEdit = QTextEdit()
descriptionLabel.setBuddy(self.descriptionEdit)
firstButton = QPushButton()
firstButton.setIcon(QIcon(":/first.png"))
prevButton = QPushButton()
prevButton.setIcon(QIcon(":/prev.png"))
nextButton = QPushButton()
nextButton.setIcon(QIcon(":/next.png"))
lastButton = QPushButton()
lastButton.setIcon(QIcon(":/last.png"))
addButton = QPushButton("&Add")
addButton.setIcon(QIcon(":/add.png"))
deleteButton = QPushButton("&Delete")
deleteButton.setIcon(QIcon(":/delete.png"))
quitButton = QPushButton("&Quit")
quitButton.setIcon(QIcon(":/quit.png"))
addButton.setFocusPolicy(Qt.NoFocus)
deleteButton.setFocusPolicy(Qt.NoFocus)
fieldLayout = QGridLayout()
fieldLayout.addWidget(catLabel, 0, 0)
fieldLayout.addWidget(self.catEdit, 0, 1, 1, 3)
fieldLayout.addWidget(nameLabel, 1, 0)
fieldLayout.addWidget(self.nameEdit, 1, 1)
fieldLayout.addWidget(IngrediantLabel, 2, 0)
fieldLayout.addWidget(self.tvIngrediants, 2, 1, 1, 3)
fieldLayout.addWidget(descriptionLabel, 3, 0)
fieldLayout.addWidget(self.descriptionEdit, 3, 1, 1, 3)
navigationLayout = QHBoxLayout()
navigationLayout.addWidget(firstButton)
navigationLayout.addWidget(prevButton)
navigationLayout.addWidget(nextButton)
navigationLayout.addWidget(lastButton)
fieldLayout.addLayout(navigationLayout, 4, 0, 1, 2)
buttonLayout = QVBoxLayout()
buttonLayout.addWidget(addButton)
buttonLayout.addWidget(deleteButton)
buttonLayout.addStretch()
buttonLayout.addWidget(quitButton)
layout = QHBoxLayout()
layout.addLayout(fieldLayout)
layout.addLayout(buttonLayout)
self.setLayout(layout)
self.model = QSqlTableModel(self)
self.model.setTable("tblRecipe")
self.model.setSort(RECIPECATEGORY, Qt.AscendingOrder)
self.model.select()
self.ingredModel = QSqlRelationalTableModel(self)
self.ingredModel.setTable("tblIngrediants")
self.ingredModel.setRelation(INGREDIANTKEY,
QSqlRelation("tblRecipe", "recipeKey", "recipeName"))
self.ingredModel.setHeaderData(INGREDIANTKEY, Qt.Horizontal, "id")
self.ingredModel.setHeaderData(INGREDIANTDESCRIPTION, Qt.Horizontal,
"Description")
self.ingredModel.setHeaderData(INGREDIANTQUANTITY, Qt.Horizontal, "Quantity")
self.ingredModel.select()
self.tvIngrediants.setModel(self.ingredModel) # connect to the model
self.tvIngrediants.setSelectionMode(QTableView.SingleSelection)
self.tvIngrediants.setSelectionBehavior(QTableView.SelectRows)
self.tvIngrediants.setColumnHidden(INGREDIANTKEY, True)
self.tvIngrediants.setColumnHidden(2, True)
self.tvIngrediants.resizeColumnsToContents()
self.mapper = QDataWidgetMapper(self)
self.mapper.setSubmitPolicy(QDataWidgetMapper.ManualSubmit)
self.mapper.setModel(self.model)
self.mapper.setItemDelegate(QSqlRelationalDelegate(self))
self.mapper.addMapping(self.catEdit, RECIPECATEGORY)
self.mapper.addMapping(self.nameEdit, RECIPENAME)
self.mapper.addMapping(self.descriptionEdit, RECIPEDESCRIPTION)
#relationModel = self.ingredModel.relationModel(INGREDIANTRECIPEKEY)
#self.tvIngrediants.setModel(relationModel)
self.mapper.addMapping(self.tvIngrediants, INGREDIANTRECIPEKEY)
self.mapper.toFirst()
self.displayIngred()
firstButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.FIRST))
prevButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.PREV))
nextButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.NEXT))
lastButton.clicked.connect(lambda: self.saveRecord(RecipeDlg.LAST))
#addButton.clicked.connect(self.addRecord)
#deleteButton.clicked.connect(self.deleteRecord)
quitButton.clicked.connect(self.accept)
self.setWindowTitle("Recipes")
def displayIngred(self):
index = self.mapper.currentIndex()
record = self.model.record(index)
id = record.value("recipeKey")
self.ingredModel.setFilter("ingrediantRecipeKey = {}".format(id))
self.ingredModel.select()
self.tvIngrediants.horizontalHeader().setVisible(
self.ingredModel.rowCount() > 0)
def reject(self):
self.accept()
def accept(self):
self.mapper.submit()
QDialog.accept(self)
def addRecord(self):
pass
def deleteRecord(self):
pass
def saveRecord(self, where):
row = self.mapper.currentIndex()
self.mapper.submit()
if where == RecipeDlg.FIRST:
row = 0
elif where == RecipeDlg.PREV:
row = 0 if row <= 1 else row - 1
elif where == RecipeDlg.NEXT:
row += 1
if row >= self.model.rowCount():
row = self.model.rowCount() - 1
elif where == RecipeDlg.LAST:
row = self.model.rowCount() - 1
self.mapper.setCurrentIndex(row)
self.displayIngred()
def main():
app = QApplication(sys.argv)
filename = os.path.join(os.path.dirname(__file__), "Recipes.db")
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName(filename)
if not db.open():
QMessageBox.warning(None, "Recipes",
"Database Error: {}".format(db.lastError().text()))
sys.exit(1)
form = RecipeDlg()
form.show()
sys.exit(app.exec_())
main()
Изображения результата:
Запись 1
Запись 4, но ингредиенты не появляются
Поскольку Stackru, похоже, не разрешает передачу файлов, я включаю содержимое своего текстового файла SQL
BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS `tblRecipe` (
`recipeKey` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`recipeName` TEXT NOT NULL,
`recipeCategory` INTEGER NOT NULL,
`recipeDescription` TEXT,
FOREIGN KEY(`recipeCategory`) REFERENCES `tblCategory`(`categoryKey`)
);
CREATE TABLE IF NOT EXISTS `tblIngrediants` (
`ingrediantKey` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`ingrediantDescription` TEXT NOT NULL,
`ingrediantRecipeKey` INTEGER NOT NULL,
`ingrediantQuantity` TEXT,
FOREIGN KEY(`ingrediantRecipeKey`) REFERENCES `tblRecipe`(`recipeKey`)
);
CREATE TABLE IF NOT EXISTS `tblCategory` (
`categoryKey` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
`categoryName` TEXT NOT NULL
);
COMMIT;
Я новичок в размещении на этом сайте, быстрый обзор справочного центра не дал мне решения.