Datenbanklogin GUI - Verbindung halten

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Byte
User
Beiträge: 63
Registriert: Dienstag 26. September 2006, 07:04

Hallo,

grüble gerade an dem Problem, wie man eine Verbindung von einem GUI Frontend zur Datenbank aufbaut.

Ich sehe dazu zwei Möglichkeiten:
1. Wenn das Programm Daten in die Datenbank schreiben will, baut es eine Verbindung zur Datenbank auf. Dazu muss man den DSN der Verbindung zur Verfügung haben

2. Es wird eine Verbindung aufgebaut, die dann von den jeweiligen Aktionen genutzt wird. Dazu muss man aber der Verbindungsobjekt speichern.

Bei beiden Möglichkeiten besteht das Problem, die Daten der Verbindung so zu halten, das man jederzeit darauf zugreifen kann. Die Verwendung von globalen Objekten soll man aber vermeiden.

Die Anwendung:

Die GUI besteht aus einem Frame der je nach Funktion ein Panel (eigenständiges Modul) lädt. Die Daten werden im Panel bearbeitet und sollen dann in die Datenbank geschrieben werden, dazu besteht ein Modul, dass die gewünschten Funktionen zum schreiben und lesen der Datenbank zur Verfügung stellt. Diesen Funktionen werden die jeweiligen Daten für die DB-Abfrage übergeben, wenn man jetzt nicht mit einem globalen Verbindungsobjekt arbeiten will, dann muss auch noch die Verbindung als Parameter übergeben werden. Was bedeutet, dass das Panel von dem der Aufruf kommt das Verbindungsobjekt kennen muss. Dazu müsste in der Anwendung das Verbindungsobjekt durchgereicht werden, das erscheint mir als kompliziert.

Habe das ganze mal versucht mit einer statischen Klasse zu lösen, und glaube das es funktioniert. Man kann auf die Funktionen der Klasse zugreifen ohne vorher eine Instanz erzeugt zu haben, trotzdem hält sie die Verbindung persistent.

Code: Alles auswählen

class ConnectionPool():
    con = []
    dsn = ""    
    def setConnection(self,host,database,user,password):
        ConnectionPool.dsn = "host=%s dbname=%s user=%s password=%s" %(host,database,user,password)
        ConnectionPool.con.append(pg.connect(ConnectionPool.dsn))
        
    def openConnection(self):
        if ConnectionPool.con:
            temp = ConnectionPool.con[0]
            del ConnectionPool.con[0]
            return temp
            
        else:
            return pg.connect(ConnectionPool.dsn)
    
    def closeConnection(self,con):
        ConnectionPool.con.append(con)

Irgendwie habe ich keine Lösung mit der ich glücklich bin, und will mich auch nicht in die falsche Richtung verrennen.

Wie wird sowas normalerweise gemacht, gibt es Beispiele?

Chistian
Byte
User
Beiträge: 63
Registriert: Dienstag 26. September 2006, 07:04

Hi Leute,

hat den gar keiner, nur einen kleinen Tip? Woran liegt es, habe ich mein Problem nicht richtig beschrieben?

Gruß Christian
BlackJack

Du hast kein Problem sondern eine Lösung beschrieben. Die sieht doch im grossen und ganzen ganz nett aus. :-)

Ich würde die Klasse weglassen und alles in ein Modul stecken. Wenn Du `self` nie benutzt, "missbrauchst" Du die Klasse nur als einfachen Namensraum, also eine Aufgabe die normalerweise Modulen zufällt.

Statt einer Liste würde sich `collections.deque()` anbieten, oder zumindest das Verwenden der Liste als Stack mit `append()` und `pop()`. Wenn Du immer das erste Element entfernst, dann werden jedesmal alle anderen Elemente der Liste umkopiert.

Was noch fehlt, ist eine Funktion, die zumindest die Verbindungen im Pool wirklich schliesst.

Wenn man die Pools (Listen oder Queues) in einem Dictionary mit den Verbindungsdaten als Schlüssel ablegt, dann könnte man ganz einfach mehrere Datenbanken oder Server gleichzeitig verwalten.
Nirven
User
Beiträge: 130
Registriert: Mittwoch 10. Mai 2006, 08:18
Wohnort: Bremerhaven

Ich kann dir nur sagen wie ich es mache, sondelich elegant ist es nicht... eigentlich so, wie du es beschrieben hast.

Beim Start des ganzen (GUI ist mit wxPython gemacht) kommt ein Login-Dialog, mit den Daten aus dem Dialog wird eine Datenbankverbindung erzeugt.
Diese wird in der wx-Applikation gespeichert, an das Hauptfenster übdergeben (wo Abfragen durchgeführt werden), und wenn von dort aus Dialoge aufgerufen werden (umd Daten der DB zuzufügen), dann wird das Verbindungsobjekt auch an die Dialoge übergeben.

Also immer durchgereicht... kompliziert ist es nicht, sonderlich elegant aber wohl auch nicht. Da die Dialoge ihren parent kennen, könnten sie auch direkt auf das Objekt zugreifen (parent.Datenbankobjekt), dann würde man sich das übergeben noch sparen, aber fürs Testen fand ich es so praktischer...
Byte
User
Beiträge: 63
Registriert: Dienstag 26. September 2006, 07:04

Hi,

danke für eure Tips.

@BlackJack
Wie mache ich es, daß die Daten im Modul erhalten bleiben? collections.deque()? das schaue ich mir an. Habe seit dem Wochenend das Buch OOP mit Python von Weigand, da hab ich das mit pop() für die Liste schon gelesen, wollte es nicht mehr ändern, weil es so auch geht, aber wo du es sagst sehe ich den Nachteil. Den Rest deiner Tips werde ich mir auch ansehen.

@Nirven
So war eigentlich mein erster Ansatz, ist eigentlich nicht unlogisch, die Verbindung mit den Daten zu übergeben. Habe halt noch das Problem, das mein Konzept immer weiter wächst, wahrscheinlich werde ich mich irgendwann nicht mehr auskennen und alles neu machen.


Gruß Christian
BlackJack

Das machst Du genau wie bei der Klasse: In einer Liste oder Queue speichern. Einfach die ``class``-Zeile löschen, alles aus der Klasse auf Modulebene rücken und das `self` aus den Argumentlisten nehmen.
Byte
User
Beiträge: 63
Registriert: Dienstag 26. September 2006, 07:04

Hi BlackJack,

dann sind die Verbindungsobjekte global, das ist dann das Minimum auf das ich mich beschränke. Aber dafür habe ich einen einfachen Zugriff darauf.

Danke
Christian
Byte
User
Beiträge: 63
Registriert: Dienstag 26. September 2006, 07:04

Hi,

bin gerade dabei, die komplette Klasse zu ändern. Dazu habe ich eine Frage.

Da die Verbindung zur Datenbank aufrechterhalten wird, kann es vorkommen, dass diese, z.B. bei unterbrochener Netzwerkverbindung, abbricht. Wenn man dann auf die Verbindung zugreift wird ein Fehler ausgelöst. Kann man den Verbindungsstatus prüfen? Das Verbindungsobject besteht ja weiterhin. Es gibt ein Attribut "status", aber das ist immer 1. Ist das überhaupt sinnvoll, so oft wird das auch nicht vorkommen.

Gruß Christian
Byte
User
Beiträge: 63
Registriert: Dienstag 26. September 2006, 07:04

Hi BlackJack,

habe auch das mit den collections.deques ausprobiert, da habe ich eine Fehlermeldung erhalten.

d = deque(verb1)
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'psycopg2._psycopg.connection' object is not iterable


Ich habe folgendes verwendet:

Code: Alles auswählen

from collections import deque
Bitte auch den vorherigen Beitrag nicht übersehen.

Gruß Christian
Antworten