sql >> Database >  >> RDS >> Database

Omgaan met SQL-databases met PyQt:de basis

Het bouwen van applicaties die gebruikmaken van een SQL-database is een vrij veel voorkomende programmeertaak. SQL-databases zijn overal en hebben geweldige ondersteuning in Python. Bij GUI-programmering biedt PyQt robuuste en platformonafhankelijke SQL-databaseondersteuning waarmee u uw databases consistent kunt maken, verbinden en beheren.

De SQL-ondersteuning van PyQt integreert volledig met de Model-View-architectuur om u te helpen bij het bouwen van databasetoepassingen.

In deze zelfstudie leert u hoe u:

  • Gebruik PyQt's SQL-ondersteuning om betrouwbaar verbinding te maken met een database
  • Voer SQL-query's uit op een database met behulp van PyQt
  • Gebruik PyQt's Model-View-architectuur in databasetoepassingen
  • Gegevens weergeven en bewerken met verschillende PyQt widgets

De voorbeelden in deze tutorial vereisen een basiskennis van de SQL-taal, in het bijzonder van het SQLite databasebeheersysteem. Enige voorkennis van GUI-programmering met Python en PyQt zal ook nuttig zijn.

Gratis bonus: 5 Thoughts On Python Mastery, een gratis cursus voor Python-ontwikkelaars die je de routekaart en de mindset laat zien die je nodig hebt om je Python-vaardigheden naar een hoger niveau te tillen.


PyQt verbinden met een SQL-database

Een applicatie verbinden met een relationele database en ervoor zorgen dat de applicatie de gegevens die in die database zijn opgeslagen, maakt, leest, bijwerkt en verwijdert, is een veelvoorkomende taak bij het programmeren. Relationele databases zijn over het algemeen georganiseerd in een reeks tabellen , of relaties . Een bepaalde rij in een tabel wordt een record genoemd of tuple , en een kolom wordt een attribuut . genoemd .

Opmerking: De term veld wordt vaak gebruikt om een ​​enkel stuk gegevens te identificeren dat is opgeslagen in een cel van een bepaald record in een tabel. Aan de andere kant, de term veldnaam wordt gebruikt om de naam van een kolom te identificeren.

Elke kolom slaat een specifiek soort informatie op, zoals namen, datums of nummers. Elke rij vertegenwoordigt een reeks nauw verwante gegevens en elke rij heeft dezelfde algemene structuur. In een database die gegevens over de werknemers in een bedrijf opslaat, vertegenwoordigt een specifieke rij bijvoorbeeld een individuele werknemer.

De meeste relationele databasesystemen gebruiken SQL (gestructureerde querytaal) voor het opvragen, manipuleren en onderhouden van de gegevens in de database. SQL is een declaratieve en domeinspecifieke programmeertaal die speciaal is ontworpen voor communicatie met databases.

Relationele databasesystemen en SQL worden tegenwoordig veel gebruikt. U vindt verschillende databasebeheersystemen, zoals SQLite, PostgreSQL, MySQL, MariaDB en vele andere. U kunt Python verbinden met elk van deze databasesystemen met behulp van een speciale Python SQL-bibliotheek.

Opmerking: Hoewel de ingebouwde SQL-ondersteuning van PyQt de voorkeursoptie is voor het beheren van SQL-databases in PyQt, kunt u ook elke andere bibliotheek gebruiken om de databaseverbinding af te handelen. Sommige van deze bibliotheken bevatten SQLAlchemy, panda's, SQLite, enzovoort.

Het gebruik van een andere bibliotheek om uw databases te beheren heeft echter enkele nadelen. U kunt niet profiteren van de integratie tussen de SQL-klassen van PyQt en de Model-View-architectuur. Bovendien voegt u extra afhankelijkheden toe aan uw toepassing.

Als het gaat om GUI-programmering met Python en PyQt, biedt PyQt een robuuste set klassen voor het werken met SQL-databases. Deze reeks klassen zal uw beste bondgenoot zijn wanneer u uw toepassing moet verbinden met een SQL-database.

Opmerking: Helaas bevat de officiële documentatie van PyQt5 enkele onvolledige secties. Om dit te omzeilen, kun je de PyQt4-documentatie, de Qt For Python-documentatie of de originele Qt-documentatie bekijken. In deze zelfstudie brengen enkele links u naar de originele Qt-documentatie, wat in de meeste gevallen een betere informatiebron is.

In deze zelfstudie leert u de basisprincipes van het gebruik van de SQL-ondersteuning van PyQt om GUI-toepassingen te maken die op betrouwbare wijze communiceren met relationele databases om gegevens te lezen, schrijven, verwijderen en weergeven.


Een databaseverbinding maken

Het koppelen van uw applicaties aan een fysieke SQL-database is een belangrijke stap in het proces van het ontwikkelen van database-applicaties met PyQt. Om deze stap met succes uit te voeren, heeft u wat algemene informatie nodig over hoe uw database is ingesteld.

U moet bijvoorbeeld weten op welk databasebeheersysteem uw database is gebouwd en mogelijk moet u ook een gebruikersnaam, een wachtwoord, een hostnaam, enzovoort hebben.

In deze zelfstudie gebruik je SQLite 3, een goed getest databasesysteem met ondersteuning op alle platforms en minimale configuratievereisten. Met SQLite kunt u rechtstreeks naar databases op uw lokale schijf lezen en schrijven zonder dat een apart serverproces nodig is. Dat maakt het een gebruiksvriendelijke optie om de ontwikkeling van databasetoepassingen te leren.

Een ander voordeel van het gebruik van SQLite is dat de bibliotheek wordt geleverd met Python en ook met PyQt, dus je hoeft niets anders te installeren om ermee aan de slag te gaan.

In PyQt kunt u een databaseverbinding maken met behulp van de QSqlDatabase klas. Deze klasse vertegenwoordigt een verbinding en biedt een interface voor toegang tot de database. Om een ​​verbinding tot stand te brengen, belt u gewoon .addDatabase() op QSqlDatabase . Deze statische methode neemt een SQL-stuurprogramma en een optionele verbindingsnaam als argumenten en retourneert een databaseverbinding:

QSqlDatabase.addDatabase(
    driver, connectionName=QSqlDatabase.defaultConnection
)

Het eerste argument, driver , is een vereist argument dat een tekenreeks bevat die de naam van een door PyQt ondersteund SQL-stuurprogramma bevat. Het tweede argument, connectionName , is een optioneel argument dat een tekenreeks bevat met de naam van de verbinding. connectionName standaard ingesteld op QSqlDatabase.defaultConnection , die normaal gesproken de tekenreeks "qt_sql_default_connection" bevat .

Als u al een verbinding heeft met de naam connectionName , dan wordt die verbinding verwijderd en vervangen door een nieuwe verbinding, en .addDatabase() geeft de nieuw toegevoegde databaseverbinding terug aan de beller.

Een aanroep naar .addDatabase() voegt een databaseverbinding toe aan een lijst met beschikbare verbindingen. Deze lijst is een algemeen register die PyQt achter de schermen bijhoudt om de beschikbare verbindingen in een applicatie bij te houden. Uw connecties registreren met een betekenisvolle connectionName stelt u in staat verschillende verbindingen in een databasetoepassing te beheren.

Nadat u een verbinding heeft gemaakt, moet u er mogelijk verschillende kenmerken aan instellen. De specifieke set kenmerken is afhankelijk van het stuurprogramma dat u gebruikt. Over het algemeen moet u kenmerken instellen zoals de databasenaam, de gebruikersnaam en het wachtwoord voor toegang tot de database.

Hier is een samenvatting van de setter-methoden die u kunt gebruiken om de meest gebruikte attributen of eigenschappen van een databaseverbinding in te stellen:

Methode Beschrijving
.setDatabaseName(name) Zet de databasenaam op name , wat een tekenreeks is die een geldige databasenaam vertegenwoordigt
.setHostName(host) Stelt de hostnaam in op host , wat een tekenreeks is die een geldige hostnaam vertegenwoordigt
.setUserName(username) Stelt de gebruikersnaam in op username , wat een tekenreeks is die een geldige gebruikersnaam vertegenwoordigt
.setPassword(password) Stelt het wachtwoord in op password , wat een tekenreeks is die een geldig wachtwoord vertegenwoordigt

Merk op dat het wachtwoord dat u als argument doorgeeft aan .setPassword() wordt opgeslagen in platte tekst en kan later worden opgehaald door .password() . aan te roepen . Dit is een ernstig beveiligingsrisico die u in uw databasetoepassingen moet vermijden. U leert een veiligere aanpak in de sectie Een databaseverbinding openen verderop in deze zelfstudie.

Een verbinding maken met een SQLite-database met behulp van QSqlDatabase , open een interactieve Python-sessie en typ de volgende code:

>>>
>>> from PyQt5.QtSql import QSqlDatabase

>>> con = QSqlDatabase.addDatabase("QSQLITE")
>>> con.setDatabaseName("contacts.sqlite")

>>> con
<PyQt5.QtSql.QSqlDatabase object at 0x7f0facec0c10>

>>> con.databaseName()
'contacts.sqlite'

>>> con.connectionName()
'qt_sql_default_connection'

Deze code maakt een databaseverbindingsobject met behulp van "QSQLITE" als het stuurprogramma van de verbinding en "contacts.sqlite" als de databasenaam van de verbinding. Aangezien u geen verbindingsnaam doorgeeft aan .addDatabase() , de nieuw gemaakte verbinding wordt uw standaardverbinding, waarvan de naam "qt_sql_default_connection" is .

In het geval van SQLite-databases is de databasenaam normaal gesproken een bestandsnaam of een pad dat de bestandsnaam van de database bevat. U kunt ook de speciale naam ":memory:" . gebruiken voor een in-memory database.



Meerdere verbindingen afhandelen

Er kunnen situaties zijn waarin u meerdere verbindingen met één database moet gebruiken. U wilt bijvoorbeeld de interacties van gebruikers met de database vastleggen met een specifieke verbinding voor elke gebruiker.

In andere situaties moet u uw toepassing mogelijk verbinden met verschillende databases. U wilt bijvoorbeeld verbinding maken met verschillende externe databases om gegevens te verzamelen om een ​​lokale database te vullen of bij te werken.

Om met deze situaties om te gaan, kunt u specifieke namen opgeven voor uw verschillende verbindingen en naar elke verbinding verwijzen met zijn naam. Als u uw databaseverbinding een naam wilt geven, geef die naam dan als tweede argument door aan .addDatabase() :

>>>
>>> from PyQt5.QtSql import QSqlDatabase

>>> # First connection
>>> con1 = QSqlDatabase.addDatabase("QSQLITE", "con1")
>>> con1.setDatabaseName("contacts.sqlite")

>>> # Second connection
>>> con2 = QSqlDatabase.addDatabase("QSQLITE", "con2")
>>> con2.setDatabaseName("contacts.sqlite")

>>> con1
<PyQt5.QtSql.QSqlDatabase object at 0x7f367f5fbf90>
>>> con2
<PyQt5.QtSql.QSqlDatabase object at 0x7f3686dd7510>

>>> con1.databaseName()
'contacts.sqlite'
>>> con2.databaseName()
'contacts.sqlite'

>>> con1.connectionName()
'con1'
>>> con2.connectionName()
'con2'

Hier maakt u twee verschillende verbindingen met dezelfde database, contacts.sqlite . Elke verbinding heeft zijn eigen verbindingsnaam. U kunt de verbindingsnaam gebruiken om later in uw code een verwijzing naar een specifieke verbinding te krijgen, afhankelijk van uw behoeften. Om dit te doen, kunt u .database() . aanroepen met een verbindingsnaam:

>>>
>>> from PyQt5.QtSql import QSqlDatabase

>>> db = QSqlDatabase.database("con1", open=False)

>>> db.databaseName()
'contacts.sqlite'
>>> db.connectionName()
'con1'

In dit voorbeeld zie je dat .database() heeft twee argumenten:

  1. connectionName bevat de verbindingsnaam die u moet gebruiken. Als u geen verbindingsnaam doorgeeft, wordt de standaardverbinding gebruikt.
  2. open bevat een Booleaanse waarde die .database() . vertelt of u de verbinding automatisch wilt openen of niet. Als open is True (standaard) en de verbinding is niet open, dan wordt de verbinding automatisch geopend.

De retourwaarde van .database() is een verwijzing naar het verbindingsobject met de naam connectionName . U kunt verschillende verbindingsnamen gebruiken om verwijzingen naar specifieke verbindingsobjecten te krijgen en deze vervolgens gebruiken om uw database te beheren.



Verschillende SQL Divers gebruiken

Tot nu toe hebt u geleerd hoe u een databaseverbinding maakt met behulp van het SQLite-stuurprogramma . Dit is niet het enige stuurprogramma dat beschikbaar is in PyQt. De bibliotheek biedt een uitgebreide set SQL-stuurprogramma's waarmee u verschillende typen databasebeheersystemen kunt gebruiken op basis van uw specifieke behoeften:

Bestuurdersnaam Databasebeheersysteem
QDB2 IBM Db2 (versie 7.1 en hoger)
QIBASE Borland InterBase
QMYSQL/MARIADB MySQL of MariaDB (versie 5.0 en hoger)
QOCI Oracle-oproepinterface
QODBC Open Database Connectivity (ODBC)
QPSQL PostgreSQL (versies 7.3 en hoger)
QSQLITE2 SQLite 2 (verouderd sinds Qt 5.14)
QSQLITE SQLite 3
QTDS Sybase Adaptive Server (verouderd sinds Qt 4.7)

De kolom Driver Name bevat de identifier strings die u moet doorgeven aan .addDatabase() als eerste argument om het bijbehorende stuurprogramma te gebruiken. In tegenstelling tot het SQLite-stuurprogramma, moet u bij het gebruik van een ander stuurprogramma mogelijk verschillende kenmerken instellen, zoals databaseName , hostName , username , en password , zodat de verbinding goed werkt.

Databasestuurprogramma's zijn afgeleid van QSqlDriver . U kunt uw eigen databasestuurprogramma's maken door QSqlDriver te subclasseren , maar dat onderwerp valt buiten het bestek van deze zelfstudie. Als u geïnteresseerd bent in het maken van uw eigen databasestuurprogramma's, bekijk dan Hoe u uw eigen databasestuurprogramma schrijft voor meer informatie.



Een databaseverbinding openen

Zodra u een databaseverbinding hebt, moet u die verbinding openen om met uw database te kunnen communiceren. Om dat te doen, roept u .open() . aan op het verbindingsobject. .open() heeft de volgende twee varianten:

  1. .open() opent een databaseverbinding met de huidige verbindingswaarden.
  2. .open(username, password) opent een databaseverbinding met de opgegeven username en password .

Beide varianten retourneren True als de verbinding is gelukt. Anders retourneren ze False . Als de verbinding niet tot stand kan worden gebracht, kunt u .lastError() . aanroepen informatie te krijgen over wat er is gebeurd. Deze functie retourneert informatie over de laatste fout gerapporteerd door de database.

Opmerking: Zoals je eerder hebt geleerd, .setPassword(password) slaat wachtwoorden op als platte tekst, wat een veiligheidsrisico is. Aan de andere kant, .open() slaat helemaal geen wachtwoorden op. Het geeft het wachtwoord rechtstreeks door aan de bestuurder bij het openen van de verbinding. Daarna verwijdert het het wachtwoord. Dus, met behulp van .open() het beheren van uw wachtwoorden is de juiste keuze als u beveiligingsproblemen wilt voorkomen.

Hier is een voorbeeld van hoe u een SQLite-databaseverbinding opent met de eerste variant van .open() :

>>>
>>> from PyQt5.QtSql import QSqlDatabase

>>> # Create the connection
>>> con = QSqlDatabase.addDatabase("QSQLITE")
>>> con.setDatabaseName("contacts.sqlite")

>>> # Open the connection
>>> con.open()
True
>>> con.isOpen()
True

In het bovenstaande voorbeeld maakt u eerst een verbinding met uw SQLite-database en opent u die verbinding met .open() . Sinds .open() retourneert True , de verbinding is gelukt. Op dit punt kunt u de verbinding controleren met .isOpen() , die True . retourneert als de verbinding open is en False anders.

Opmerking: Als je .open() . aanroept op een verbinding die het SQLite-stuurprogramma gebruikt en het databasebestand niet bestaat, wordt automatisch een nieuw en leeg databasebestand gemaakt.

In toepassingen in de echte wereld moet u ervoor zorgen dat u een geldige verbinding met uw database hebt voordat u bewerkingen op uw gegevens probeert uit te voeren. Anders kan uw toepassing kapot gaan en mislukken. Wat als u bijvoorbeeld geen schrijfrechten hebt voor de map waarin u dat databasebestand probeert te maken? U moet ervoor zorgen dat u eventuele fouten oplost die kunnen optreden tijdens het openen van een verbinding.

Een veelgebruikte manier om .open() . aan te roepen is om het in een voorwaardelijke verklaring te verpakken. Hiermee kunt u fouten afhandelen die kunnen optreden bij het openen van de verbinding:

>>>
>>> import sys
>>> from PyQt5.QtSql import QSqlDatabase

>>> # Create the connection
>>> con = QSqlDatabase.addDatabase("QSQLITE")
>>> con.setDatabaseName("contacts.sqlite")

>>> # Open the connection and handle errors
>>> if not con.open():
...     print("Unable to connect to the database")
...     sys.exit(1)

Wrapping van de aanroep naar .open() in een voorwaardelijke instructie kunt u elke fout afhandelen die optreedt wanneer u de verbinding opent. Op deze manier kunt u uw gebruikers informeren over eventuele problemen voordat de applicatie wordt uitgevoerd. Merk op dat de applicatie wordt afgesloten met een afsluitstatus van 1 , die gewoonlijk wordt gebruikt om een ​​programmafout aan te geven.

In het bovenstaande voorbeeld gebruik je .open() in een interactieve sessie, dus je gebruikt print() om foutmeldingen aan de gebruikers te presenteren. Echter, in GUI-toepassingen, in plaats van print() . te gebruiken , gebruik je normaal gesproken een QMessageBox voorwerp. Met QMessageBox , kunt u kleine dialoogvensters maken om informatie aan uw gebruikers te presenteren.

Hier is een voorbeeld van een GUI-toepassing die een manier illustreert om verbindingsfouten af ​​te handelen:

 1import sys
 2
 3from PyQt5.QtSql import QSqlDatabase
 4from PyQt5.QtWidgets import QApplication, QMessageBox, QLabel
 5
 6# Create the connection
 7con = QSqlDatabase.addDatabase("QSQLITE")
 8con.setDatabaseName("/home/contacts.sqlite")
 9
10# Create the application
11app = QApplication(sys.argv)
12
13# Try to open the connection and handle possible errors
14if not con.open():
15    QMessageBox.critical(
16        None,
17        "App Name - Error!",
18        "Database Error: %s" % con.lastError().databaseText(),
19    )
20    sys.exit(1)
21
22# Create the application's window
23win = QLabel("Connection Successfully Opened!")
24win.setWindowTitle("App Name")
25win.resize(200, 100)
26win.show()
27sys.exit(app.exec_())

De if statement in regel 14 controleert of de verbinding is mislukt. Als de /home/ directory niet bestaat of als je geen toestemming hebt om erin te schrijven, dan is de aanroep van .open() mislukt omdat het databasebestand niet kan worden gemaakt. In deze situatie is de uitvoeringsstroom voert de if . in instructiecodeblok en toont een bericht op het scherm.

Als u het pad wijzigt naar een andere map waarin u kunt schrijven, dan is de aanroep naar .open() zal slagen en je ziet een venster met het bericht Connection Successfully Opened! Je hebt ook een nieuw databasebestand met de naam contacts.sqlite in de geselecteerde map.

Merk op dat je None doorgeeft als de ouder van het bericht omdat je op het moment dat het bericht wordt weergegeven, nog geen venster hebt gemaakt, dus je hebt geen levensvatbare ouder voor het berichtvenster.




SQL-query's uitvoeren met PyQt

Met een volledig functionele databaseverbinding bent u klaar om met uw database aan de slag te gaan. Om dat te doen, kunt u op tekenreeksen gebaseerde SQL-query's en QSqlQuery . gebruiken voorwerpen. QSqlQuery stelt u in staat om elke vorm van SQL-query in uw database uit te voeren. Met QSqlQuery , kunt u DML-instructies (Data Manipulation Language) uitvoeren, zoals SELECT , INSERT , UPDATE , en DELETE , evenals DDL-instructies (Data Definition Language), zoals CREATE TABLE enzovoort.

De constructor van QSqlQuery heeft verschillende variaties, maar in deze tutorial leer je er twee:

  1. QSqlQuery(query, connection) construeert een query-object met behulp van een op tekenreeksen gebaseerde SQL query en een database connection . Als u geen verbinding opgeeft, of als de opgegeven verbinding ongeldig is, wordt de standaard databaseverbinding gebruikt. Als query is geen lege string, dan wordt deze meteen uitgevoerd.

  2. QSqlQuery(connection) maakt een query-object met behulp van connection . Als connection ongeldig is, wordt de standaardverbinding gebruikt.

U kunt ook QSqlQuery . maken objecten zonder argumenten aan de constructor door te geven. In dat geval zal de query de standaard databaseverbinding gebruiken, indien aanwezig.

Om een ​​query uit te voeren, moet u .exec() . aanroepen op het query-object. U kunt .exec() . gebruiken op twee verschillende manieren:

  1. .exec(query) voert de op tekenreeks gebaseerde SQL-query uit die is opgenomen in query . Het retourneert True als de zoekopdracht succesvol was en anders False retourneert .

  2. .exec() voert een eerder voorbereide SQL-query uit. Het retourneert True als de zoekopdracht succesvol was en anders False retourneert .

Opmerking: PyQt implementeert ook variaties van QSqlQuery.exec() met de naam .exec_() . Deze bieden achterwaartse compatibiliteit met oudere versies van Python waarin exec was een sleutelwoord van de taal.

Nu u de basis kent van het gebruik van QSqlQuery om SQL-query's te maken en uit te voeren, bent u klaar om te leren hoe u uw kennis in de praktijk kunt brengen.


Statische SQL-query's uitvoeren

Om te beginnen met het maken en uitvoeren van query's met PyQt, start je je favoriete code-editor of IDE en maak je een Python-script met de naam queries.py . Sla het script op en voeg de volgende code toe:

 1import sys
 2
 3from PyQt5.QtSql import QSqlDatabase, QSqlQuery
 4
 5# Create the connection
 6con = QSqlDatabase.addDatabase("QSQLITE")
 7con.setDatabaseName("contacts.sqlite")
 8
 9# Open the connection
10if not con.open():
11    print("Database Error: %s" % con.lastError().databaseText())
12    sys.exit(1)
13
14# Create a query and execute it right away using .exec()
15createTableQuery = QSqlQuery()
16createTableQuery.exec(
17    """
18    CREATE TABLE contacts (
19        id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
20        name VARCHAR(40) NOT NULL,
21        job VARCHAR(50),
22        email VARCHAR(40) NOT NULL
23    )
24    """
25)
26
27print(con.tables())

In dit script begin je met het importeren van de modules en klassen waarmee je gaat werken. Vervolgens maakt u een databaseverbinding met behulp van .addDatabase() met het SQLite-stuurprogramma. U stelt de databasenaam in op "contacts.sqlite" en open de verbinding.

Om uw eerste query te maken, start u QSqlQuery zonder enige argumenten. Met het query-object op zijn plaats, roept u .exec() . aan , waarbij een op tekenreeksen gebaseerde SQL-query als argument wordt doorgegeven. Dit soort zoekopdracht staat bekend als een statische zoekopdracht omdat het geen parameters van buiten de query krijgt.

De bovenstaande SQL-query maakt een nieuwe tabel met de naam contacts in uw databank. Die tabel heeft de volgende vier kolommen:

Kolom Inhoud
id Een geheel getal met de primaire sleutel van de tabel
name Een tekenreeks met de naam van een contact
job Een string met de functietitel van een contactpersoon
email Een string met het e-mailadres van een contactpersoon

De laatste regel in het bovenstaande script drukt de lijst met tabellen in uw database af. Als u het script uitvoert, ziet u dat een nieuw databasebestand met de naam contacts.sqlite wordt aangemaakt in uw huidige directory. Je krijgt ook zoiets als ['contacts', 'sqlite_sequence'] afgedrukt op uw scherm. Deze lijst bevat de namen van de tabellen in uw database.

Opmerking: Een op tekenreeksen gebaseerde SQL-query moet een geschikte syntaxis gebruiken volgens de specifieke SQL-database die u opvraagt. Als de syntaxis verkeerd is, dan .exec() negeert de zoekopdracht en retourneert False .

In het geval van SQLite kan de query slechts één instructie tegelijk bevatten.

.exec() . aanroepen op een QSqlQuery object is een veelgebruikte manier om direct op tekenreeksen gebaseerde SQL-query's op uw databases uit te voeren, maar wat als u uw query's van tevoren wilt voorbereiden voor latere uitvoering? Dat is het onderwerp van het volgende gedeelte.



Dynamische zoekopdrachten uitvoeren:tekenreeksopmaak

Tot nu toe hebt u geleerd hoe u statische query's op een database uitvoert. Statische zoekopdrachten zijn zoekopdrachten die geen parameters accepteren , dus de query wordt uitgevoerd zoals deze is. Hoewel deze query's redelijk nuttig zijn, moet u soms query's maken die gegevens ophalen als reactie op bepaalde invoerparameters.

Query's die tijdens de uitvoering parameters accepteren, staan ​​bekend als dynamische query's . Met behulp van parameters kunt u de query verfijnen en gegevens ophalen als reactie op specifieke parameterwaarden. Verschillende waarden zullen verschillende resultaten opleveren. U kunt invoerparameters in een query opnemen door een van de volgende twee benaderingen te gebruiken:

  1. Bouw de query dynamisch op, met behulp van tekenreeksopmaak om parameterwaarden te interpoleren.
  2. Bereid de query voor met behulp van tijdelijke aanduiding-parameters en bind vervolgens specifieke waarden aan parameters.

Met de eerste benadering kunt u snel dynamische query's maken. Om deze benadering veilig te gebruiken, moet u er echter zeker van zijn dat uw parameterwaarden afkomstig zijn van een vertrouwde bron. Anders kunt u te maken krijgen met SQL-injectie-aanvallen.

Hier is een voorbeeld van hoe u tekenreeksopmaak kunt gebruiken om dynamische query's in PyQt te maken:

>>>
>>> from PyQt5.QtSql import QSqlQuery, QSqlDatabase

>>> con = QSqlDatabase.addDatabase("QSQLITE")
>>> con.setDatabaseName("contacts.sqlite")
>>> con.open()
True

>>> name = "Linda"
>>> job = "Technical Lead"
>>> email = "[email protected]"

>>> query = QSqlQuery()
>>> query.exec(
...     f"""INSERT INTO contacts (name, job, email)
...     VALUES ('{name}', '{job}', '{email}')"""
... )
True

In dit voorbeeld gebruikt u een f-tekenreeks om een ​​dynamische query te maken door specifieke waarden te interpoleren in een op tekenreeksen gebaseerde SQL-query. De laatste zoekopdracht voegt gegevens toe aan uw contacts tabel, die nu gegevens bevat over Linda .

Opmerking: Verderop in deze zelfstudie ziet u hoe u de gegevens die in een database zijn opgeslagen, kunt ophalen en erin kunt navigeren.

Merk op dat om dit soort dynamische query's te laten werken, u ervoor moet zorgen dat de in te voegen waarden het juiste gegevenstype hebben. U gebruikt dus enkele aanhalingstekens rond de tijdelijke aanduiding in de f-tekenreeks, omdat die waarden tekenreeksen moeten zijn.



Dynamische zoekopdrachten uitvoeren:tijdelijke aanduiding-parameters

De tweede benadering voor het uitvoeren van dynamische zoekopdrachten vereist dat u uw zoekopdrachten van tevoren voorbereidt met behulp van een sjabloon met plaatsaanduidingen voor parameters. PyQt ondersteunt twee stijlen voor tijdelijke aanduidingen voor parameters:

  1. Oracle-stijl gebruikt benoemde tijdelijke aanduidingen zoals :name of :email .
  2. ODBC-stijl gebruikt een vraagteken (? ) als positionele tijdelijke aanduiding.

Houd er rekening mee dat deze stijlen niet in dezelfde query kunnen worden gemengd. U kunt Benaderingen van bindende waarden bekijken voor extra voorbeelden van het gebruik van tijdelijke aanduidingen.

Opmerking: ODBC staat voor Open Database Connectivity.

Om dit soort dynamische query's in PyQt te maken, maakt u eerst een sjabloon met een tijdelijke aanduiding voor elke queryparameter en geeft u die sjabloon vervolgens als argument door aan .prepare() , die de querysjabloon parseert, compileert en voorbereidt voor uitvoering. Als de sjabloon problemen heeft, zoals een SQL-syntaxisfout, dan .prepare() kan de sjabloon niet compileren en retourneert False .

Als het voorbereidingsproces slaagt, prepare() retourneert True . Daarna kunt u een specifieke waarde aan elke parameter doorgeven met behulp van .bindValue() met benoemde of positionele parameters of met behulp van .addBindValue() met positionele parameters. .bindValue() heeft de volgende twee varianten:

  1. .bindValue(placeholder, val)
  2. .bindValue(pos, val)

In de eerste variant, placeholder vertegenwoordigt een tijdelijke aanduiding in Oracle-stijl. In de tweede variant, pos staat voor een op nul gebaseerd geheel getal met de positie van een parameter in de query. In beide varianten, val bevat de waarde die aan een specifieke parameter moet worden gebonden.

.addBindValue() voegt een waarde toe aan de lijst met tijdelijke aanduidingen met behulp van positionele binding. Dit betekent dat de volgorde van de aanroepen naar .addBindValue() bepaalt welke waarde wordt gebonden aan elke tijdelijke aanduiding-parameter in de voorbereide query.

Om voorbereide zoekopdrachten te gaan gebruiken, kunt u een INSERT INTO . maken SQL-instructie om uw database te vullen met enkele voorbeeldgegevens. Ga terug naar het script dat je hebt gemaakt in de sectie Statische SQL-query's uitvoeren en voeg de volgende code toe direct na de aanroep van print() :

28# Creating a query for later execution using .prepare()
29insertDataQuery = QSqlQuery()
30insertDataQuery.prepare(
31    """
32    INSERT INTO contacts (
33        name,
34        job,
35        email
36    )
37    VALUES (?, ?, ?)
38    """
39)
40
41# Sample data
42data = [
43    ("Joe", "Senior Web Developer", "[email protected]"),
44    ("Lara", "Project Manager", "[email protected]"),
45    ("David", "Data Analyst", "[email protected]"),
46    ("Jane", "Senior Python Developer", "[email protected]"),
47]
48
49# Use .addBindValue() to insert data
50for name, job, email in data:
51    insertDataQuery.addBindValue(name)
52    insertDataQuery.addBindValue(job)
53    insertDataQuery.addBindValue(email)
54    insertDataQuery.exec()

De eerste stap is het maken van een QSqlQuery voorwerp. Dan bel je .prepare() op het query-object. In dit geval gebruikt u de ODBC-stijl voor de tijdelijke aanduidingen. Uw zoekopdracht heeft waarden voor de name van uw contactpersoon , job , en email , dus je hebt drie tijdelijke aanduidingen nodig. Sinds de id kolom is een automatisch verhoogd geheel getal, u hoeft er geen waarden voor op te geven.

Vervolgens maakt u enkele voorbeeldgegevens om de database te vullen. data bevat een lijst met tupels en elke tupel bevat drie items:de naam, functie en e-mail van elk contact.

De laatste stap is om de waarden die u wilt doorgeven aan elke tijdelijke aanduiding te binden en vervolgens .exec() aan te roepen. om de vraag uit te voeren. Om dat te doen, gebruik je een for lus. De luskop pakt elke tuple uit in data in drie afzonderlijke variabelen met handige namen. Vervolgens roept u .addBindValue() . aan on the query object to bind the values to the placeholders.

Note that you’re using positional placeholders , so the order in which you call .addBindValue() will define the order in which each value is passed to the corresponding placeholder.

This approach for creating dynamic queries is handy when you want to customize your queries using values that come from your user’s input. Anytime you take the user’s input to complete a query on a database, you face the security risk of SQL injection.

In PyQt, combining .prepare() , .bindValue() , and .addBindValue() fully protects you against SQL injection attacks, so this is the way to go when you’re taking untrusted input to complete your queries.



Navigating the Records in a Query

If you execute a SELECT statement, then your QSqlQuery object will retrieve zero or more records from one or more tables in your database. The query will hold records containing data that matches the query’s criteria. If no data matches the criteria, then your query will be empty.

QSqlQuery provides a set of navigation methods that you can use to move throughout the records in a query result:

Method Retrieves
.next() The next record
.previous() The previous record
.first() The first record
.last() The last record
.seek(index, relative=False) The record at position index

All these methods position the query object on the retrieved record if that record is available. Most of these methods have specific rules that apply when using them. With these methods, you can move forward, backward, or arbitrarily through the records in a query result. Since they all return either True or False , you can use them in a while loop to navigate all the records in one go.

These methods work with active queries . A query is active when you’ve successfully run .exec() on it, but the query isn’t finished yet. Once an active query is on a valid record, you can retrieve data from that record using .value(index) . This method takes a zero-based integer number, index , and returns the value at that index (column) in the current record.

Opmerking: If you execute a SELECT * type of query, then the columns in the result won’t follow a known order. This might cause problems when you use .value() to retrieve the value at a given column because there’s no way of knowing if you’re using the right column index.

You’ll look at a few examples of how to use some of the navigation methods to move throughout a query below. But first, you need to create a connection to your database:

>>>
>>> from PyQt5.QtSql import QSqlDatabase, QSqlQuery

>>> con = QSqlDatabase.addDatabase("QSQLITE")
>>> con.setDatabaseName("contacts.sqlite")
>>> con.open()
True

Here, you create and open a new connection to contacts.sqlite . If you’ve been following along with this tutorial so far, then this database already contains some sample data. Now you can create a QSqlQuery object and execute it on that data:

>>>
>>> # Create and execute a query
>>> query = QSqlQuery()
>>> query.exec("SELECT name, job, email FROM contacts")
True

This query retrieves data about the name , job , and email of all the contacts stored in the contacts tafel. Since .exec() returned True , the query was successful and is now an active query. You can navigate the records in this query using any of the navigation methods you saw before. You can also retrieve the data at any column in a record using .value() :

>>>
>>> # First record
>>> query.first()
True

>>> # Named indices for readability
>>> name, job, email = range(3)

>>> # Retrieve data from the first record
>>> query.value(name)
'Linda'

>>> # Next record
>>> query.next()
True
>>> query.value(job)
'Senior Web Developer'

>>> # Last record
>>> query.last()
True
>>> query.value(email)
'[email protected]'

With the navigation methods, you can move around the query result. With .value() , you can retrieve the data at any column in a given record.

You can also iterate through all the records in your query using a while loop along with .next() :

>>>
>>> query.exec()
True

>>> while query.next():
...     print(query.value(name), query.value(job), query.value(email))
...
Linda Technical Lead [email protected]
Joe Senior Web Developer [email protected]
...

With .next() , you navigate all the records in a query result. .next() works similar to the iterator protocol in Python. Once you’ve iterated over the records in a query result, .next() starts returning False until you run .exec() again. A call to .exec() retrieves data from a database and places the query object’s internal pointer one position before the first record, so when you call .next() , you get the first record again.

You can also loop in reverse order using .previous() :

>>>
>>> while query.previous():
...     print(query.value(name), query.value(job), query.value(email))
...
Jane Senior Python Developer [email protected]
David Data Analyst [email protected]
...

.previous() works similar to .next() , but the iteration is done in reverse order. In other words, the loop goes from the query pointer’s position back to the first record.

Sometimes you might want to get the index that identifies a given column in a table by using the name of that column. To do that, you can call .indexOf() on the return value of .record() :

>>>
>>> query.first()
True

>>> # Get the index of name
>>> name = query.record().indexOf("name")

>>> query.value(name)
'Linda'

>>> # Finish the query object if unneeded
>>> query.finish()
>>> query.isActive()
False

The call to .indexOf() on the result of .record() returns the index of the "name" kolom. If "name" doesn’t exist, then .indexOf() retourneert -1 . This is handy when you use a SELECT * statement in which the order of columns is unknown. Finally, if you’re done with a query object, then you can turn it inactive by calling .finish() . This will free the system memory associated with the query object at hand.




Closing and Removing Database Connections

In practice, some of your PyQt applications will depend on a database, and others won’t. An application that depends on a database often creates and opens a database connection just before creating any window or graphical component and keeps the connection open until the application is closed.

On the other hand, applications that don’t depend on a database but use a database to provide some of their functionalities typically connect to that database only when needed, if at all. In these cases, you can close the connection after use and free the resources associated with that connection, such as system memory.

To close a connection in PyQt, you call .close() on the connection. This method closes the connection and frees any acquired resources. It also invalidates any associated QSqlQuery objects because they can’t work properly without an active connection.

Here’s an example of how to close an active database connection using .close() :

>>>
>>> from PyQt5.QtSql import QSqlDatabase

>>> con = QSqlDatabase.addDatabase("QSQLITE")
>>> con.setDatabaseName("contacts.sqlite")

>>> con.open()
True
>>> con.isOpen()
True

>>> con.close()
>>> con.isOpen()
False

You can call .close() on a connection to close it and free all its associated resources. To make sure that a connection is closed, you call .isOpen() .

Note that QSqlQuery objects remain in memory after closing their associated connection, so you must make your queries inactive by calling .finish() or .clear() , or by deleting the QSqlQuery object before closing the connection. Otherwise, residual memory is left out in your query object.

You can reopen and reuse any previously closed connection. That’s because .close() doesn’t remove connections from the list of available connections, so they remain usable.

You can also completely remove your database connections using .removeDatabase() . To do this safely, first finish your queries using .finish() , then close the database using .close() , and finally remove the connection. You can use .removeDatabase(connectionName) to remove the database connection called connectionName from the list of available connections. Removed connections are no longer available for use in the application at hand.

To remove the default database connection, you can call .connectionName() on the object returned by .database() and pass the result to .removeDatabase() :

>>>
>>> # The connection is closed but still in the list of connections
>>> QSqlDatabase.connectionNames()
['qt_sql_default_connection']

>>> # Remove the default connection
>>> QSqlDatabase.removeDatabase(QSqlDatabase.database().connectionName())

>>> # The connection is no longer in the list of connections
>>> QSqlDatabase.connectionNames()
[]

>>> # Try to open a removed connection
>>> con.open()
False

Here, the call to .connectionNames() returns the list of available connections. In this case, you have only one connection, the default. Then you remove the connection using .removeDatabase() .

Opmerking: Before closing and removing a database connection, you need to make sure that everything that uses the connection is deleted or set to use a different data source. Otherwise, you can have a resource leak .

Since you need a connection name to use .removeDatabase() , you call .connectionName() on the result of .database() to get the name of the default connection. Finally, you call .connectionNames() again to make sure that the connection is no longer in the list of available connections. Trying to open a removed connection will return False because the connection no longer exists.



Displaying and Editing Data With PyQt

A common requirement in GUI applications that use databases is the ability to load, display, and edit data from the database using different widgets. Table, list, and tree widgets are commonly used in GUIs to manage data.

PyQt provides two different kind of widgets for managing data:

  1. Standard widgets include internal containers for storing data.
  2. View widgets don’t maintain internal data containers but use models to access data.

For small GUI applications that manage small databases, you can use the first approach. The second approach is handy when you’re building complex GUI applications that manage large databases.

The second approach takes advantage of PyQt’s Model-View programming. With this approach, you have widgets that represent views such as tables, lists, and trees on one hand and model classes that communicate with your data on the other hand.


Understanding PyQt’s Model-View Architecture

The Model-View-Controller (MVC) design pattern is a general software pattern intended to divide an application’s code into three general layers, each with a different role.

The model takes care of the business logic of the application, the view provides on-screen representations, and the controller connects the model and the view to make the application work.

Qt provides a custom variation of MVC. They call it the Model-View architecture, and it’s available for PyQt as well. The pattern also separates the logic into three components:

  1. Models communicate with and access the data. They also define an interface that’s used by views and delegates to access the data. All models are based on QAbstractItemModel . Some commonly used models include QStandardItemModel , QFileSystemModel , and SQL-related models.

  2. Views are responsible for displaying the data to the user. They also have similar functionality to the controller in the MVC pattern. All views are based on QAbstractItemView . Some commonly used views are QListView , QTableView , and QTreeView .

  3. Delegates paint view items and provide editor widgets for modifying items. They also communicate back with the model if an item has been modified. The base class is QAbstractItemDelegate .

Separating classes into these three components implies that changes on models will be reflected on associated views or widgets automatically, and changes on views or widgets through delegates will update the underlying model automatically.

In addition, you can display the same data in different views without the need for multiple models.



Using Standard Widget Classes

PyQt provides a bunch of standard widgets for displaying and editing data in your GUI applications. These standard widgets provide views such as tables, trees, and lists. They also provide an internal container for storing data and convenient delegates for editing the data. All these features are grouped into a single class.

Here are three of these standard classes:

Standard Class Displays
QListWidget A list of items
QTreeWidget A hierarchical tree of items
QTableWidget A table of items

QTableWidget is arguably the most popular widget when it comes to displaying and editing data. It creates a 2D array of QTableWidgetItem objects. Each item holds an individual value as a string. All these values are displayed and organized in a table of rows and columns.

You can perform at least the following operations on a QTableWidget object:

  • Editing the content of its items using delegate objects
  • Adding new items using .setItem()
  • Setting the number of rows and columns using .setRowCount() and .setColumnCount()
  • Adding vertical and horizontal header labels using setHorizontalHeaderLabels() and .setVerticalHeaderLabels

Here’s a sample application that shows how to use a QTableWidget object to display data in a GUI. The application uses the database you created and populated in previous sections, so if you want to run it, then you need to save the code into the same directory in which you have the contacts.sqlite database:

If you double-click any cell of the table, then you’ll be able to edit the content of the cell. However, your changes won’t be saved to your database.

Here’s the code for your application:

 1import sys
 2
 3from PyQt5.QtSql import QSqlDatabase, QSqlQuery
 4from PyQt5.QtWidgets import (
 5    QApplication,
 6    QMainWindow,
 7    QMessageBox,
 8    QTableWidget,
 9    QTableWidgetItem,
10)
11
12class Contacts(QMainWindow):
13    def __init__(self, parent=None):
14        super().__init__(parent)
15        self.setWindowTitle("QTableView Example")
16        self.resize(450, 250)
17        # Set up the view and load the data
18        self.view = QTableWidget()
19        self.view.setColumnCount(4)
20        self.view.setHorizontalHeaderLabels(["ID", "Name", "Job", "Email"])
21        query = QSqlQuery("SELECT id, name, job, email FROM contacts")
22        while query.next():
23            rows = self.view.rowCount()
24            self.view.setRowCount(rows + 1)
25            self.view.setItem(rows, 0, QTableWidgetItem(str(query.value(0))))
26            self.view.setItem(rows, 1, QTableWidgetItem(query.value(1)))
27            self.view.setItem(rows, 2, QTableWidgetItem(query.value(2)))
28            self.view.setItem(rows, 3, QTableWidgetItem(query.value(3)))
29        self.view.resizeColumnsToContents()
30        self.setCentralWidget(self.view)
31
32def createConnection():
33    con = QSqlDatabase.addDatabase("QSQLITE")
34    con.setDatabaseName("contacts.sqlite")
35    if not con.open():
36        QMessageBox.critical(
37            None,
38            "QTableView Example - Error!",
39            "Database Error: %s" % con.lastError().databaseText(),
40        )
41        return False
42    return True
43
44app = QApplication(sys.argv)
45if not createConnection():
46    sys.exit(1)
47win = Contacts()
48win.show()
49sys.exit(app.exec_())

Here’s what’s happening in this example:

  • Lines 18 to 20 create a QTableWidget object, set the number of columns to 4 , and set user-friendly labels for each column’s header.
  • Line 21 creates and executes a SELECT SQL query on your database to get all the data in the contacts table.
  • Line 22 starts a while loop to navigate the records in the query result using .next() .
  • Line 24 increments the number of rows in the table by 1 using .setRowCount() .
  • Lines 25 to 28 add items of data to your table using .setItem() . Note that since the values in the id columns are integer numbers, you need to convert them into strings to be able to store them in a QTableWidgetItem voorwerp.

.setItem() takes three arguments:

  1. row holds a zero-based integer that represents the index of a given row in the table.
  2. column holds a zero-based integer that represents the index of a given column in the table.
  3. item holds the QTableWidgetItem object that you need to place at a given cell in the table.

Finally, you call .resizeColumnsToContents() on your view to adjust the size of the columns to their content and provide a better rendering of the data.

Displaying and editing database tables using standard widgets can become a challenging task. That’s because you’ll have two copies of the same data. In other words you’ll have a copy of the data in two locations:

  1. Outside the widget, in your database
  2. Inside the widget, in the widget’s internal containers

You’re responsible for synchronizing both copies of your data manually, which can be an annoying and error-prone operation. Luckily, you can use PyQt’s Model-View architecture to avoid most of these problems, as you’ll see in the following section.



Using View and Model Classes

PyQt’s Model-View classes eliminate the problems of data duplication and synchronization that may occur when you use standard widget classes to build database applications. The Model-View architecture allows you to use several views to display the same data because you can pass one model to many views.

Model classes provide an application programming interface (API) that you can use to manipulate data. View classes provide convenient delegate objects that you can use to edit data in the view directly. To connect a view with a given module, you need to call .setModel() on the view object.

PyQt offers a set of view classes that support the Model-View architecture:

View Class Displays
QListView A list of items that take values directly from a model class
QTreeView A hierarchical tree of items that take values directly from a model class
QTableView A table of items that take values directly from a model class

You can use these view classes along with model classes to create your database applications. This will make your applications more robust, faster to code, and less error-prone.

Here are some of the model classes that PyQt provides for working with SQL databases:

Model Class Beschrijving
QSqlQueryModel A read-only data model for SQL queries
QSqlTableModel An editable data model for reading and writing records in a single table
QSqlRelationalTableModel An editable data model for reading and writing records in a relational table

Once you’ve connected one of these models to a physical database table or query, you can use them to populate your views. Views provide delegate objects that allow you to modify the data directly in the view. The model connected to the view will update the data in your database to reflect any change in the view. Note that you don’t have to update the data in the database manually. The model will do that for you.

Here’s an example that shows the basics of how to use a QTableView object and a QSqlTableModel object together to build a database application using PyQt’s Model-View architecture:

To edit the data in a cell of the table, you can double-click the cell. A convenient delegate widget will show in the cell, allowing you to edit its content. Then you can hit Enter to save the changes.

The ability to automatically handle and save changes in the data is one of the more important advantages of using PyQt’s Model-View classes. The Model-View architecture will improve your productivity and reduce the errors that can appear when you have to write data manipulation code by yourself.

Here’s the code to create the application:

 1import sys
 2
 3from PyQt5.QtCore import Qt
 4from PyQt5.QtSql import QSqlDatabase, QSqlTableModel
 5from PyQt5.QtWidgets import (
 6    QApplication,
 7    QMainWindow,
 8    QMessageBox,
 9    QTableView,
10)
11
12class Contacts(QMainWindow):
13    def __init__(self, parent=None):
14        super().__init__(parent)
15        self.setWindowTitle("QTableView Example")
16        self.resize(415, 200)
17        # Set up the model
18        self.model = QSqlTableModel(self)
19        self.model.setTable("contacts")
20        self.model.setEditStrategy(QSqlTableModel.OnFieldChange)
21        self.model.setHeaderData(0, Qt.Horizontal, "ID")
22        self.model.setHeaderData(1, Qt.Horizontal, "Name")
23        self.model.setHeaderData(2, Qt.Horizontal, "Job")
24        self.model.setHeaderData(3, Qt.Horizontal, "Email")
25        self.model.select()
26        # Set up the view
27        self.view = QTableView()
28        self.view.setModel(self.model)
29        self.view.resizeColumnsToContents()
30        self.setCentralWidget(self.view)
31
32def createConnection():
33    con = QSqlDatabase.addDatabase("QSQLITE")
34    con.setDatabaseName("contacts.sqlite")
35    if not con.open():
36        QMessageBox.critical(
37            None,
38            "QTableView Example - Error!",
39            "Database Error: %s" % con.lastError().databaseText(),
40        )
41        return False
42    return True
43
44app = QApplication(sys.argv)
45if not createConnection():
46    sys.exit(1)
47win = Contacts()
48win.show()
49sys.exit(app.exec_())

Here’s what’s happening in this code:

  • Line 18 creates an editable QSqlTableModel voorwerp.
  • Line 19 connects your model with the contacts table in your database using .setTable() .
  • Line 20 sets the edit strategy of the model to OnFieldChange . This strategy allows the model to automatically update the data in your database if the user modifies any of the data directly in the view.
  • Lines 21 to 24 set some user-friendly labels to the horizontal headers of the model using .setHeaderData() .
  • Line 25 loads the data from your database and populates the model by calling .select() .
  • Line 27 creates the table view object to display the data contained in the model.
  • Line 28 connects the view with the model by calling .setModel() on the view with your data model as an argument.
  • Line 29 calls .resizeColumnsToContents() on the view object to adjust the table to its content.

Dat is het! You now have a fully-functional database application.




Using SQL Databases in PyQt:Best Practices

When it comes to using PyQt’s SQL support effectively, there are some best practices that you might want to use in your applications:

  • Favor PyQt’s SQL support over Python standard library or third-party libraries to take advantage of the natural integration of these classes with the rest of PyQt’s classes and infrastructure, mostly with the Model-View architecture.

  • Use previously prepared dynamic queries with placeholders for parameters and bind values to those parameters using .addBindValue() and .bindValue() . This will help prevent SQL injection attacks.

  • Handle errors that can occur when opening a database connection to avoid unexpected behaviors and application crashes.

  • Close and remove unneeded database connections and queries to free any acquired system resources.

  • Minimize the use of SELECT * queries to avoid problems when retrieving data with .value() .

  • Pass your passwords to .open() instead of to .setPassword() to avoid the risk of compromising your security.

  • Take advantage of PyQt’s Model-View architecture and its integration with PyQt’s SQL support to make your applications more robust.

This list isn’t complete, but it’ll help you make better use of PyQt’s SQL support when developing your database applications.



Conclusie

Using PyQt’s built-in support to work with SQL databases is an important skill for any Python developer who’s creating PyQt GUI applications and needs to connect them to a database. PyQt provides a consistent set of classes for managing SQL databases.

These classes fully integrate with PyQt’s Model-View architecture, allowing you to develop GUI applications that can manage databases in a user-friendly way.

In this tutorial, you’ve learned how to:

  • Use PyQt’s SQL support to connect to a database
  • Execute SQL queries on a database with PyQt
  • Build database applications using PyQt’s Model-View architecture
  • Display and edit data from a database using PyQt widgets

With this knowledge, you can improve your productivity when creating nontrivial database applications and make your GUI applications more robust.



  1. Alles wat u moet weten over coderingsstandaarden voor SQL-query's

  2. Islands T-SQL-uitdaging

  3. INDIEN BESTAAT voorwaarde werkt niet met PLSQL

  4. De naam van de huidige functie binnen de functie krijgen met plpgsql