Tvorba GUI pomocí PyQT 2/2

1. Databáze

Knihovna QT obsahuje rozhraní pro připojení k řadě databází. V následujícím příkladu si ukážeme, jak se připojit k databázi typu SQLite a trochu se seznámíme i s dotazovacím jazykem SQL. V PyQt5 se pro práci s databázemi na systémové úrovni používá třída QSqlDatabase, pro manipulaci s daty slouží třída QSqlQuery.

SQLite

SQLite je relační databázový systém, který není na rozdíl od větších systémů založen na architektuře server-klient, ale je tvořen jen jednoduchochou knihovnou (napsanou v C), které poskytuje rozhraní k lokálnímu datovému úložišti. Každá databáze je ukládána do samostatného souboru. Výhodou je snadná přenositelnost a to i mezi platformami, navíc existuje i řada desktopových aplikací, které umožňují práci s databázemi, např. SQLiteStudio.

Na rozdíl od jiných systémů není třeba datababázi explicitně vytvářet, pokud neexistuje, je vytvořena automaticky při otevření:

from PyQt5.QtSql import *
 
db = QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName('studenti.db')
db.open()

Pro práci s databázemi slouží dotazovací jazyk SQL, resp. jeho podmnožina. Data jsou uložena v tabulkách, jejichž sloupce mají název a datový typ. V první fázi budeme pořebovat vytvořit tabulku, specifikovat její sloupce a naplnit ji daty. V příkladu vytvoříme záznam v podobě tabulky seznam, naplněné daty studentů s náledujícími vlastnostmi:

  • id - číslo záznamu, datový typ int, v rámci tabulky automaticky přidělené a automaticky inkrementované
  • jmeno - jméno studenta, datový typ varchar
  • prijmeni - příjmení studenta, datový typ varchar

Pro vytvoření a naplnění tabulky využijeme metodu QSqlQuery.exec()

sql = QSqlQuery()
sql.exec("create table seznam (id int primary key, jmeno varchar(20), prijmeni varchar(20))")
sql.exec("insert into seznam values (1, 'Jan', 'Novak')")
sql.exec("insert into seznam values (2, 'Jana', 'Novakova')")

Manipulace s daty

S daty v databáze lze manipulovat různými způsoby

q = QSqlQuery("select * from seznam")
 
rec = q.record()
 
jmeno = rec.indexOf("jmeno") # index pole "jmeno"
while q.next():
    print (q.value(jmeno))   # vypsani vsech jmen

Pokud je třeba ovlivňovat podobu SQL dotazu programem, nejjednodušší metodou je sestavení textového řetězce

jmeno = input("zadej jmeno: ")
prijmeni = input("zadej prijmeni: ")
 
q = QSqlQuery("insert into seznam values (1, {}, {}".format(jmeno, prijmeni))
q.exec()

Třída QSqlQuery obsahuje sofistikovanější nástoj - binding

q = QSqlQuery()
q.prepare("INSERT INTO seznam (id, jmeno, prijmeni) VALUES (:id, :jmeno, :prijmeni)")
q.bindValue(":id", 1001)
q.bindValue(":jmeno", "Bart")
q.bindValue(":prijmeni", "Simpson")
q.exec()

Třída QSqlTableModel poskytuje vysokoúrovňový pohled na data uložená v tabulkách - poskytuje editovatelný model pro zápis a čtení jednotlivých záznamů v tabulce. Model je možné použít přímo v komponentě QTableView. Pro editaci je možné změnit některou z následujících strategií:

  • QSqlTableModel.OnFieldChange - všechny změny modelu budou aplikovány ihned po editaci
  • QSqlTableModel.OnRowChange - změny budou aplikovány ve chvíli kdy uživatel zvolí jiný řádek
  • QSqlTableModel.OnManualSubmit - všechny změny modelu budou uloženy v mezipaměti, dokud nebude zavolána metoda submitAll() nebo revertAll()

model = QtSql.QSqlTableModel()
model.setTable('seznam') 
model.setEditStrategy(QtSql.QSqlTableModel.OnFieldChange)
 
model.select()

Model je pak použit v instanci třídy QTableView:

view = QTableView()
view.setModel(model)
view.setWindowTitle(title)

Kompletní příklad by pak mohl vypadat takto:

from PyQt5.QtWidgets import *
from PyQt5.QtSql import *
from PyQt5.QtCore import *
 
def initializeModel(model):
   model.setTable('seznam')
   model.setEditStrategy(QSqlTableModel.OnFieldChange)
   model.select()
   model.setHeaderData(0, Qt.Horizontal, "ID")
   model.setHeaderData(1, Qt.Horizontal, "Jmeno")
   model.setHeaderData(2, Qt.Horizontal, "Prijmeni")
 
def createView(title, model):
   view = QTableView()
   view.setModel(model)
   view.setWindowTitle(title)
   return view
 
def addrow():
   ret = model.insertRows(model.rowCount(), 1)
 
def findrow(i):
   delrow = i.row()
 
if __name__ == '__main__':
 
   app = QApplication([])
   db = QSqlDatabase.addDatabase('QSQLITE')
   db.setDatabaseName('studenti.db')
   model = QSqlTableModel()
   delrow = -1
   initializeModel(model)
 
   view1 = createView("Table Model (View 1)", model)
   view1.clicked.connect(findrow)
 
   dlg = QDialog()
   layout = QVBoxLayout()
   layout.addWidget(view1)
 
   button = QPushButton("Add a row")
   button.clicked.connect(addrow)
   layout.addWidget(button)
 
   btn1 = QPushButton("del a row")
   btn1.clicked.connect(lambda: model.removeRow(view1.currentIndex().row()))
   layout.addWidget(btn1)
 
   dlg.setLayout(layout)
   dlg.setWindowTitle("Database Demo")
   dlg.show()
 
   app.exec()

courses/bab37zpr/solutions/lab14.txt · Last modified: 2020/12/10 17:37 by viteks