[Sqlite] Alternativer Zugriff auf Objekte ohne Indexangabe

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Benutzeravatar
Dennis89
User
Beiträge: 524
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

vielen Dank für eure Antworten. Da hätte ich das wieder unnötig kompliziert geschrieben.

Ich antworte erst jetzt, da ich mich erst etwas mit 'classmethod' beschäftigen musste. Aber so sieht das ja jetzt echt ordentlich aus 🙂
Jetzt schaue ich mir die Tage mal an, wie sich die Datenbank am besten aufteilen lässt und dann schaue ich wie weit ich komme.

Grüße und einen schönen Rest-Sonntag
Dennis
“A ship is always safe at the shore, but that is not what it is built for.”
Benutzeravatar
Dennis89
User
Beiträge: 524
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo zusammen,

testweise habe ich jetzt eine Datenbank mit zwei Tabellen erstellt und die Klasse 'Kinetics' aus __blackjack__'s Beispielcode wie die Klasse 'Thermodynamics' aufgebaut. Das funktioniert so weit auch.

Ich hatte hier im Forum vor ein paar Wochen auch ein Thema eröffnet, in dem ich gefragt habe, wie ich mit 'tkinter' mehrere Frames von der Logik trenne. Mit diesen Infos versuche ich zur Zeit ein GUI zu schreiben, mit dem ich die Berechnung aus den obenen genannten Klassen ausführen kann. Grundlage dafür ist [url="viewtopic.php?p=408300#p408300"]dieser Code[/code].

Programmablauf:
- Begrüßungsbildschirm mit einem Button, durch den das nächste Frame aufgerufen wird
- Eingabebildschirm mit einem Drop-Down Menü mit allen Maschinentypen, die in der Datenbank in der Spalte "Maschine_type" zu finden sind. Zwei Eingabefelder, einmal zur Eingabe einer Fläche und einmal zur Eingabe einer Gastemperatur. Button für Zurück und für Weiter.
-Ausgabebildschirm: Gibt einen berechneten Wert aus der 'Thermodynamics'-Klasse und einen aus der 'Kinetics'-Klasse aus. Button zum Anfangsbildschirm.

Das Problem ist jetzt nicht mehr wie es zu Beginn dieses Themas war, dennoch beziehe ich mich mal auf folgendes Zitat, weil dass gerade mit meinem Problem zu tun hat:
__deets__ hat geschrieben: Samstag 23. Juli 2022, 09:04 Dein problem hier erfordert nicht, dass du die Werte bei bedarf einliest.
Jetzt muss ich die Werte zwei mal einlesen(?). Ich benötige im "Eingabebildschirm" alle Werte aus der "Maschine_type"-Spalte und erst wenn wenn in dem Drop-Down-Menü eine Maschine ausgewählt wurde, kann ich die benötigten Werte für die Berechnungen auslesen.

Ich habe Probleme das Programm zu strukturieren. Wenn ich dabei bleibe, das ich eine Klasse 'Machine', 'Thermodynamic' und 'Kinetics' habe und für jedes Frame auch eine eigene Klasse, wo erstelle ich eine Instanz der Machine-Klasse? Öffne ich die Datenbankverbindung "schon" in der 'main'-Funktion und übergebe die Verbindung bis ich sie brauche?
Bin ich jetzt auf dem ganz falschen Weg?

Ich poste hier jetzt mal noch den Code wie er gerade in der Entwicklung ist. Mir ist bewusst, dass da Klassen teilweise Argumente haben, die nicht übergeben wurden und das bis jetzt noch gar keine Datenbankverbindung eingebaut ist. Ich habe jetzt beide Codebeispiele hier zusammen gebaut (man könnte auch kopiert sagen) und ich weis nicht wie ich die ordentlich vereine und/oder ob die überhaupt so strukturiert sind, dass sie ordentlich vereinbar sind. Also das hat alles gar nichts mit irgendwelchen "echten" Daten zu tun und der Sinn ist auch "nur" dass ich lerne wie man so etwas macht. Deswegen lösche ich auch bei Bedarf wieder alles und fange noch einmal anders von vorne an, wenn ihr meint das wäre besser.

Code: Alles auswählen

#!/usr/bin/env python3
import sqlite3
from contextlib import closing
import tkinter as tk
from functools import partial

DATABASE = "database.db"


class CalculationApp(tk.Frame):
    def __init__(self, master, connection):
        tk.Frame.__init__(self, master)
        self.frames = {}
        home_page = Home(self)
        home_page.grid(row=0, column=0, sticky=tk.NSEW)
        entry_page = Entry(self)
        entry_page.grid(row=0, column=0, sticky=tk.NSEW)
        result_page = Result(self, connection)
        result_page.grid(row=0, column=0, sticky=tk.NSEW)
        self.frames["Home"] = home_page
        self.frames["Entry"] = entry_page
        self.frames["Result"] = result_page
        self.show_page("Home")

    def show_page(self, page_name):
        self.frames[page_name].tkraise()

    def get_page(self, page_name):
        return self.frames[page_name]


class Home(tk.Frame):
    def __init__(self, controller):
        tk.Frame.__init__(self)
        self.controller = controller
        headline = tk.Label(self, text="Hier gehts zur Berechnung")
        headline.grid(row=0, column=1)
        go_to_entry_page = tk.Button(
            self, text=">>", command=partial(self.controller.show_page, "Entry")
        )
        go_to_entry_page.grid(row=1, column=3)


class Entry(tk.Frame):
    def __init__(self, controller, machine_types):
        tk.Frame.__init__(self)
        self.controller = controller
        self.machine_types = machine_types
        tk.Label(self, text="Bitte Maschine auswählen").grid(row=0, column=1)
        machine_choice = tk.OptionMenu(self, "", *self.machine_types)
        machine_choice.grid(row=1, column=0)
        tk.Label(self, text="Bitte Fläche eingeben").grid(row=2, column=1)
        self.area = tk.Entry(self)
        self.area.grid(row=3, column=1)
        tk.Label(self, text="Bitte Gastemperatur eingeben").grid(row=4, column=1)
        self.inlet_gas_temperature = tk.Entry(self)
        self.inlet_gas_temperature.grid(row=5, column=1)
        tk.Button(
            self, text="Berechne", command=partial(self.controller.show_page, "Result")
        ).grid(row=3, column=3)
        tk.Button(
            self, text="<<", command=partial(self.controller.show_page, "Home")
        ).grid(row=3, column=0)

    @classmethod
    def from_database(cls, connection):
        with closing(connection.cursor()) as cursor:
            cursor.execute("SELECT MACHINE_TYPE" " FROM KINETICS")
            machine_types = cursor.fetchall()
            print(machine_types)
        return cls(machine_types)


class Result(tk.Frame):
    def __init__(self, controller, connection):
        tk.Frame.__init__(self)
        self.controller = controller
        self.outlet_gas_temperature = tk.Label(
            self, text=machine.thermodynamic_properties
        )
        self.outlet_gas_temperature.grid(row=0, column=1)
        self.force = tk.Label(self, text=machine.kinetics_properties)
        self.force.grid(row=1, column=1)
        button = tk.Button(
            self, text="Startseite", command=partial(controller.show_page, "Home")
        )
        button.grid(row=2, column=1)


class Kinetics:
    def __init__(self, area, force):
        self.area = area
        self.force = force

    @property
    def pressure(self):
        return self.force / self.area

    @classmethod
    def from_database(cls, connection, machine_type, area):
        with closing(connection.cursor()) as cursor:
            cursor.execute(
                ("SELECT FORCE" " FROM KINETICS" " WHERE machine_type=?"),
                [machine_type],
            )
            force = cursor.fetchone()[0]
        return cls(area, force)


class Thermodynamic:
    def __init__(self, inlet_gas_temperature, volume_in, volume_out):
        self.inlet_gas_temperature = inlet_gas_temperature
        self.volume_in = volume_in
        self.volume_out = volume_out

    @property
    def outlet_gas_temperature(self):
        return self.volume_out * self.inlet_gas_temperature / self.volume_in

    @classmethod
    def from_database(cls, connection, machine_type, inlet_gas_temperature):
        with closing(connection.cursor()) as cursor:
            cursor.execute(
                (
                    "SELECT volume_in, volume_out"
                    " FROM THERMODYNAMICS"
                    " WHERE machine_type=?"
                ),
                [machine_type],
            )
            volume_in, volume_out = cursor.fetchone()
        return cls(inlet_gas_temperature, volume_in, volume_out)


class Machine:
    def __init__(self, thermodynamic_properties, kinetics_properties):
        self.thermodynamic_properties = thermodynamic_properties
        self.kinetics_properties = kinetics_properties

    @classmethod
    def from_database(cls, connection, machine_type, inlet_gas_temperature, area):
        return cls(
            Thermodynamic.from_database(
                connection, machine_type, inlet_gas_temperature
            ),
            Kinetics.from_database(connection, machine_type, area),
        )


def main():
    root = tk.Tk()
    root.title("Berechnungsprogramm")
    app = CalculationApp(root)
    app.mainloop()


if __name__ == "__main__":
    main()
Vielen Danke schon für die Mühe, die ihr aufbringt um das alles durchzulesen!

Achja, wie immer verusche ich erst mal gerne mit euren Hinweisen den Code selbst zu schreiben und wenn ich scheitere freue ich mich über Codebeispiele.

Grüße
Dennis
“A ship is always safe at the shore, but that is not what it is built for.”
Benutzeravatar
Dennis89
User
Beiträge: 524
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Abend,

ich habe das jetzt mal mit der Datenbankabfrage so zusammen gefrickelt.

Code: Alles auswählen

#!/usr/bin/env python3
import sqlite3
from contextlib import closing
import tkinter as tk
from functools import partial

DATABASE = "database.db"


class CalculationApp(tk.Frame):
    def __init__(self, master, connection):
        tk.Frame.__init__(self, master)
        self.frames = {}
        home_page = Home(self)
        home_page.grid(row=0, column=0, sticky=tk.NSEW)
        entry_page = Entry(self, connection)
        entry_page.grid(row=0, column=0, sticky=tk.NSEW)
        result_page = Result(self)
        result_page.grid(row=0, column=0, sticky=tk.NSEW)
        self.frames["Home"] = home_page
        self.frames["Entry"] = entry_page
        self.frames["Result"] = result_page
        self.show_page("Home")

    def show_page(self, page_name):
        self.frames[page_name].tkraise()

    def get_page(self, page_name):
        return self.frames[page_name]


class Home(tk.Frame):
    def __init__(self, controller):
        tk.Frame.__init__(self)
        self.controller = controller
        headline = tk.Label(self, text="Hier gehts zur Berechnung")
        headline.grid(row=0, column=1)
        go_to_entry_page = tk.Button(
            self, text=">>", command=partial(self.controller.show_page, "Entry")
        )
        go_to_entry_page.grid(row=1, column=3)


class Entry(tk.Frame):
    def __init__(self, controller, connection):
        tk.Frame.__init__(self)
        self.controller = controller
        self.connection = connection
        self.machine_types = self.from_database()
        self.machine_choice = tk.StringVar()
        tk.Label(self, text="Bitte Maschine auswählen").grid(row=0, column=1)
        machine_choice = tk.OptionMenu(self, self.machine_choice, *self.machine_types)
        machine_choice.grid(row=1, column=0)
        tk.Label(self, text="Bitte Fläche eingeben").grid(row=2, column=1)
        self.area = tk.Entry(self)
        self.area.grid(row=3, column=1)
        tk.Label(self, text="Bitte Gastemperatur eingeben").grid(row=4, column=1)
        self.inlet_gas_temperature = tk.Entry(self)
        self.inlet_gas_temperature.grid(row=5, column=1)
        tk.Button(self, text="Berechne", command=self.show_result).grid(row=3, column=3)
        tk.Button(
            self, text="<<", command=partial(self.controller.show_page, "Home")
        ).grid(row=3, column=0)

    def from_database(self):
        with closing(self.connection.cursor()) as cursor:
            cursor.execute("SELECT MACHINE_TYPE" " FROM KINETICS")
            return cursor.fetchone()

    def show_result(self):
        machine = Machine.from_database(
            self.connection,
            self.machine_choice.get(),
            int(self.inlet_gas_temperature.get()),
            int(self.area.get()),
        )
        self.controller.get_page("Result").outlet_gas_temperature.config(
            text=machine.thermodynamic_properties.outlet_gas_temperature
        )
        self.controller.get_page("Result").force.config(
            text=machine.kinetics_properties.pressure
        )
        self.controller.show_page("Result")


class Result(tk.Frame):
    def __init__(self, controller):
        tk.Frame.__init__(self)
        self.controller = controller
        self.outlet_gas_temperature = tk.Label(self, text="")
        self.outlet_gas_temperature.grid(row=0, column=1)
        self.force = tk.Label(self, text="")
        self.force.grid(row=1, column=1)
        button = tk.Button(
            self, text="Startseite", command=partial(controller.show_page, "Home")
        )
        button.grid(row=2, column=1)


class Kinetics:
    def __init__(self, area, force):
        self.area = area
        self.force = force

    @property
    def pressure(self):
        return self.force / self.area

    @classmethod
    def from_database(cls, connection, machine_type, area):
        with closing(connection.cursor()) as cursor:
            cursor.execute(
                (
                    "SELECT FORCE" 
                    " FROM KINETICS" 
                    " WHERE machine_type=?"
                ),
                [machine_type],
            )
            force = cursor.fetchone()[0]
        return cls(area, force)


class Thermodynamic:
    def __init__(self, inlet_gas_temperature, volume_in, volume_out):
        self.inlet_gas_temperature = inlet_gas_temperature
        self.volume_in = volume_in
        self.volume_out = volume_out

    @property
    def outlet_gas_temperature(self):
        return self.volume_out * self.inlet_gas_temperature / self.volume_in

    @classmethod
    def from_database(cls, connection, machine_type, inlet_gas_temperature):
        with closing(connection.cursor()) as cursor:
            cursor.execute(
                (
                    "SELECT volume_in, volume_out"
                    " FROM THERMODYNAMICS"
                    " WHERE machine_type=?"
                ),
                [machine_type],
            )
            volume_in, volume_out = cursor.fetchone()
        return cls(inlet_gas_temperature, volume_in, volume_out)


class Machine:
    def __init__(self, thermodynamic_properties, kinetics_properties):
        self.thermodynamic_properties = thermodynamic_properties
        self.kinetics_properties = kinetics_properties

    @classmethod
    def from_database(cls, connection, machine_type, inlet_gas_temperature, area):
        return cls(
            Thermodynamic.from_database(
                connection, machine_type, inlet_gas_temperature
            ),
            Kinetics.from_database(connection, machine_type, area),
        )


def main():
    with closing(
        sqlite3.connect(DATABASE, detect_types=sqlite3.PARSE_DECLTYPES)
    ) as connection:
        root = tk.Tk()
        root.title("Berechnungsprogramm")
        app = CalculationApp(root, connection)
        app.mainloop()


if __name__ == "__main__":
    main()
Grüße
Dennis
“A ship is always safe at the shore, but that is not what it is built for.”
Sirius3
User
Beiträge: 16232
Registriert: Sonntag 21. Oktober 2012, 17:20

In Entry.from_database fragst Du einen beliebiegen machine_type ab, weist aber das Ergebnis der Variable machine_types zu. Da passt was nicht. Bei einem besseren Methodennamen, wie z.B. get_machine_type oder get_machine_types wäre es klarer, wo der Fehler liegt.
Benutzeravatar
Dennis89
User
Beiträge: 524
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen und danke für die Antwort.

Der Fehler wäre mir vielleicht aufgefallen, wenn meine Testdatenbank nicht nur einen Eintrag hätte.

Code: Alles auswählen

class Entry(tk.Frame):
    def __init__(self, controller, connection):
        tk.Frame.__init__(self)
        self.controller = controller
        self.connection = connection
        self.machine_types = self.get_machine_types()
        self.machine_choice = tk.StringVar()
        tk.Label(self, text="Bitte Maschine auswählen").grid(row=0, column=1)
        machine_choice = tk.OptionMenu(self, self.machine_choice, *self.machine_types)
        machine_choice.grid(row=1, column=0)
        tk.Label(self, text="Bitte Fläche eingeben").grid(row=2, column=1)
        self.area = tk.Entry(self)
        self.area.grid(row=3, column=1)
        tk.Label(self, text="Bitte Gastemperatur eingeben").grid(row=4, column=1)
        self.inlet_gas_temperature = tk.Entry(self)
        self.inlet_gas_temperature.grid(row=5, column=1)
        tk.Button(self, text="Berechne", command=self.show_result).grid(row=3, column=3)
        tk.Button(
            self, text="<<", command=partial(self.controller.show_page, "Home")
        ).grid(row=3, column=0)

    def get_machine_types(self):
        with closing(self.connection.cursor()) as cursor:
            cursor.execute("SELECT MACHINE_TYPE FROM KINETICS")
            machine_types = cursor.fetchall()
            return machine_types
Wäre der oben gepostet Code nun ein einigermaßen ordetliches Grundgerüst um ein solches Berechnungsprogramm aufzubauen?

Grüße
Dennis
“A ship is always safe at the shore, but that is not what it is built for.”
Antworten