Projekterstellung mit GUI

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Das `db.close()` könnte man wie schon gesagt auch mit einem ``with`` und `closing()` erledigen.
das wiederrum habe ich dann offensichtlich nicht verstanden. Habe ja in den ganzen Funktionen dieses closing drin. Heißt das dann, dass ich die die db Connection gar nicht mehr schliessen muss?

Ich überlege gerade wie ich diese Schleife und die passende Kondition dazu baue.....


Mit dem
gut das cleanup nehme ich aus dem except raus. da es im finally abgearbeitet wird.
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: In den Funktionen erstellst und schliesst Du Cursor-Objekte und verwendest zum deterministischen schliessen `closing()` und ``with``. In der Hauptfunktion erstellst und schliesst Du die Verbindung zur Datenbank. Dort verwendest Du zum deterministischen schliessen ``finally`` und einen expliziten Aufruf der `close()`-Methode auf der Verbindung. Das kann man natürlich auch machen, musste man sogar bevor es die ``with``-Anweisung gab. Mit ``with`` wird aber die Lebensdauer der Verbindung deutlicher, weil man sehr leicht sehen kann wo der Anfang und wo das Ende ist, weil es sich um einen eingerückten Block extra für diesen Zweck handelt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Danke für die Hilfe,

ich habe den MySQldb.connection.close in die def connect unter ein finally: gepackt.
Unten in der main() bin ich noch nicht Glücklich. Scheinbar muss in dem finally block der main() was drin stehen, sonst spinnt die rum.

Für die Prüfung ob der User bereits einen Eintrag hat, habe ich grade noch keine Lösung. :-(


Auch der except KeyBoardInterrrupt ist noch am falschen Ort....


Code: Alles auswählen

#!/usr/bin/python3

import os
import RPi.GPIO as gpio
import MFRC522
import MySQLdb
import MySQLdb.cursors
from contextlib import closing
import time

DB_HOST = "XXX"
DB_USER = "XX"
DB_PASSWORD = "XXX"

ablaufaktiv = True

def connect():
        try:
            return MySQLdb.connect(host=DB_HOST, port=3307,
            user=DB_USER , passwd=DB_PASSWORD, db="Schiessbuch",
            cursorclass=MySQLdb.cursors.DictCursor)
        finally:
            MySQLdb.connection.close

def benutzer_anzeigen(db):
    print()
    with closing(db.cursor()) as cursor:
        cursor.execute("""Select tbl_Benutzer.ID, tbl_Benutzer.UName, tbl_Benutzer.UVorname
            FROM tbl_Benutzer INNER JOIN tbl_Karten ON tbl_Benutzer.ID = tbl_Karten.UserID""")
        for row in cursor:
           print( row["ID"], row["UName"], row["UVorname"])


def benutzer_registriert(db, user_id):
    print()
    with closing(db.cursor()) as cursor:
        cursor.execute("""SELECT tbl_Schiesstand.UserID
                        FROM tbl_Schiesstand
                        Where  tbl_Schiesstand.UserID = %d AND  (DATE(tbl_Schiesstand.Beginn) = CURDATE() AND NOT DATE(tbl_Schiesstand.Ende) = CURDATE())""" % (user_id))
        
        if cursor.fetchone():
            print("Du bist bereits registriert")
            time.sleep(5)
            return False
        else: 
            return True
            
        


def stand_anzeigen(db):
    print()
    with closing(db.cursor()) as cursor:
        cursor.execute("Select ID, StandLang From tbl_Stand") 
        for row in cursor:
            print( row["ID"], row["StandLang"])



def kaliber_anzeigen(db, stand_id):
    print()
    with closing(db.cursor()) as cursor:
        cursor.execute("""Select tbl_Kaliber.ID, tbl_Kaliber.KaliberLang
            From tbl_Stand INNER JOIN tbl_Kaliber ON tbl_Stand.ID = tbl_Kaliber.StandID
            Where tbl_Stand.ID = %s""", (stand_id,))
        for row in cursor:
            print( row["ID"], row["KaliberLang"])



def schuetze_anlegen(db, user_id, stand_id, platz, kaliber_id, standaufsicht):
    print()
    with closing(db.cursor()) as cursor:
        sql_query = """INSERT INTO `tbl_Schiesstand` (`UserID`, `StandID`, `Platz`, `KaliberID`, `Beginn`, `Standaufsicht`) VALUES (%s, %s, %s, %s, NOW(), %s)"""
        data = (user_id, stand_id, platz, kaliber_id, standaufsicht) 
        cursor.execute(sql_query, data) 
        db.commit()
        
        
    print("Du wurdest erfolgreich registriert") 
    time.sleep(5)
    
    

def input_int(prompt):
    while True:
        try:
            print()
            return int(input(prompt))
        except ValueError:
            print("Fehler: Keine Zahl eingegeben.")
            
#Funktion für die RFID Karten zulesen

def karte_erkennen():
    continue_reading = True
    MIFAREReader = MFRC522.Reader(0, 0, 22)

    # This loop keeps checking for chips. If one is near it will get the UID and authenticate
    while continue_reading:
        # Scan for cards
        (status, TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

        # If a card is found
        if status == MIFAREReader.MI_OK:
            print("Card detected")

        # Get the UID of the card
        (status, uid) = MIFAREReader.MFRC522_Anticoll()

        # If we have the UID, continue
        if status == MIFAREReader.MI_OK:
            # Print UID
            print("Card read UID: " + str(uid[0]) + "," + str(uid[1]) + "," + str(uid[2]) + "," + str(uid[3])+ "," + str(uid[4]))
            MIFAREReader.AntennaOff()
            continue_reading=False
            return str(uid[0])+str(uid[1])+str(uid[2])+str(uid[3])+str(uid[4])


def Gpio():
    # Show no warnings
    GPIO.setwarnings(False)
    # Use GPIO pin numbers
    GPIO.setmode(GPIO.BOARD)        

def cardread():
    cardId=karte_erkennen()
    return cardId


def kartenid_Userid(db, cardID):
    print()
    with closing(db.cursor()) as cursor:
        cursor.execute("""SELECT tbl_Benutzer.ID
                            FROM tbl_Benutzer INNER JOIN tbl_Karten ON tbl_Benutzer.ID = tbl_Karten.UserID
                            WHERE tbl_Karten.KartenNummer=%s """) %(cardID)
        for row in cursor:
            print( row["ID"])
            return row["ID"]



def main():
   while ablaufaktiv:
        try:
            os.system('clear')
            print("Schiessbuch")
            print()
            print("Bitte erfasse deine Daten!")
            #print()
            #print("Bitte Scanne deine Karte!")
            db = connect()


            #cardread()
            
            
            benutzer_anzeigen(db)
            user_id = input_int("Bitte deine User ID eingeben: ")
                
            benutzer_registriert(db, user_id)
            #benutzer_registriert(db, kartenid_Userid)
            
            stand_anzeigen(db)
            stand_id = input_int("Bitte Stand eingeben: ")
            
            kaliber_anzeigen(db, stand_id)
            kaliber_id = input_int("Bitte Kaliber eingeben: ")
            
            platz = input_int("Auf welchem Stand schiesst du?: ")
            
            standaufsicht = 0
            schuetze_anlegen(db, user_id, stand_id, platz, kaliber_id, standaufsicht)
        
        except KeyboardInterrupt:
            print("Abbruch")
            
        finally: 
            print("Ende")
       
        
        

if __name__ == '__main__':
    main()


Den Keyboard Interput habe ich mal so zusammen kopiert:

Code: Alles auswählen

def keyboardInterruptHandler(signal, frame):
    print("Abbruch durch Benutzer (ID: {}) wurde gedrückt.".format(signal))
    exit(0)

signal.signal(signal.SIGINT, keyboardInterruptHandler)
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Habe eine Idee:

Code: Alles auswählen

ef main():
   while ablaufaktiv:
        try:
            os.system('clear')
            print("Schiessbuch")
            print()
            print("Bitte erfasse deine Daten!")
            #print()
            #print("Bitte Scanne deine Karte!")
            db = connect()


            #cardread()
            
            
            benutzer_anzeigen(db)
            user_id = input_int("Bitte deine User ID eingeben: ")
                
          if not benutzer_registriert(db, user_id):
            #benutzer_registriert(db, kartenid_Userid)
            
                continue
            
            stand_anzeigen(db)
            stand_id = input_int("Bitte Stand eingeben: ")
            
            kaliber_anzeigen(db, stand_id)
            kaliber_id = input_int("Bitte Kaliber eingeben: ")
            
            platz = input_int("Auf welchem Stand schiesst du?: ")
            
            standaufsicht = 0
            schuetze_anlegen(db, user_id, stand_id, platz, kaliber_id, standaufsicht)
        
        except KeyboardInterrupt:
            print("Abbruch")
            
        finally: 
            print("Ende")
       
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: Jetzt schliesst Du die Verbindung gar nicht mehr. In der `connect()`-Funktion machst Du im ``finally``-Zweig effektiv nichts. Du hast da einen Ausdruck der zur ungebundenen Methode `close` von `mysql.connection` ausgewertet wird, was keinen Sinn macht.

Und natürlich muss in jedem Block etwas stehen, weil die Python-Grammatik das verlangt. Aber man muss ja keinen ``finally``-Zweig hinschreiben wenn man den nicht braucht.

Die Ausgabe „Du bist bereits registriert“ und die 5-sekündige Pause gehören nicht in die Funktion die testet ob der Benutzer angemeldet ist oder nicht. Das ist Benutzerinteraktion, die von diesem Test unabhängig ist.

Du formatierst dort immer noch einen Wert in die SQL-Abfrage als Zeichenkette hinein.

Die Bedingung zu `Beginn` und `Ende` in der Datenbank sieht unsinnig bis falsch aus. Wenn der Benutzer immer nur einmal irgendwo angemeldet sein darf, also nur eine offene Endzeit existieren darf, dann ist die Bedingung einfach nur ob `Ende` den Wert NULL hat.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

__blackjack__ hat geschrieben: Mittwoch 20. März 2019, 15:14 @matze1708: Jetzt schliesst Du die Verbindung gar nicht mehr. In der `connect()`-Funktion machst Du im ``finally``-Zweig effektiv nichts. Du hast da einen Ausdruck der zur ungebundenen Methode `close` von `mysql.connection` ausgewertet wird, was keinen Sinn macht.

Und natürlich muss in jedem Block etwas stehen, weil die Python-Grammatik das verlangt. Aber man muss ja keinen ``finally``-Zweig hinschreiben wenn man den nicht braucht.

Die Ausgabe „Du bist bereits registriert“ und die 5-sekündige Pause gehören nicht in die Funktion die testet ob der Benutzer angemeldet ist oder nicht. Das ist Benutzerinteraktion, die von diesem Test unabhängig ist.

Du formatierst dort immer noch einen Wert in die SQL-Abfrage als Zeichenkette hinein.

Die Bedingung zu `Beginn` und `Ende` in der Datenbank sieht unsinnig bis falsch aus. Wenn der Benutzer immer nur einmal irgendwo angemeldet sein darf, also nur eine offene Endzeit existieren darf, dann ist die Bedingung einfach nur ob `Ende` den Wert NULL hat.

Ich habe bereits den Print Befehl und das sleep runter in die Main in das if not gezogen.

Wie muss das in dem connect finally aussehen? Dachte ich habe das so geschlossen.... mhmm


Die Formatierung schaue ich mir nochmal an. War da auch der Meinung das es passt. Weil es auch geht.
In der Spalte Ende steht immer ein 0000-00-00 00:00:00 wert von DB Modell her drine. Kein NULL. Könnte ich aber DB seitig auch anpassen.
Dann müsste ich schauen ob der User aktuell KEIN Ende Wert hat. Aber Heute gestartet ist ?! Eigentlich reicht Ende ist leer oder 0 oder NULL.

Code: Alles auswählen

def main():
   while ablaufaktiv:
        try:
            os.system('clear')
            print("Schiessbuch")
            print()
            print("Bitte erfasse deine Daten!")
            #print()
            #print("Bitte Scanne deine Karte!")
            db = connect()


            #cardread()
            
            
            benutzer_anzeigen(db)
            user_id = input_int("Bitte deine User ID eingeben: ")
                
            if not benutzer_registriert(db, user_id):
            #benutzer_registriert(db, kartenid_Userid)
                print("Du bist bereits registriert")
                time.sleep(5)
                continue
            
            stand_anzeigen(db)
            stand_id = input_int("Bitte Stand eingeben: ")
            
            kaliber_anzeigen(db, stand_id)
            kaliber_id = input_int("Bitte Kaliber eingeben: ")
            
            platz = input_int("Auf welchem Stand schiesst du?: ")
            
            standaufsicht = 0
            schuetze_anlegen(db, user_id, stand_id, platz, kaliber_id, standaufsicht)
        
        except KeyboardInterrupt:
            print("Abbruch")
            
        finally: 
            print("Ende")
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Das prüfen auf NULL ist geändert und auch der Standardwert in der DB Tabelle.

Aber am SQL String bin ich noch dran. da weiss ich grade nicht was falsch ist.

Code: Alles auswählen

def benutzer_registriert(db, user_id):
    print()
    with closing(db.cursor()) as cursor:
        cursor.execute("""SELECT tbl_Schiesstand.UserID
                        FROM tbl_Schiesstand
                        Where  tbl_Schiesstand.UserID = %d AND  tbl_Schiesstand.Ende IS NULL""" % (user_id))
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: Du benutzt Zeichenkettenformatierung mit dem ``%``-Operator. Bei den anderen `execute()`-Aufrufen machst Du das doch richtig.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Bei dem connect kann ich es mir nur so aktuell denken

Code: Alles auswählen

def connect():
        try:
            conn = MySQLdb.connect(host=DB_HOST, port=3307,
            user=DB_USER , passwd=DB_PASSWORD, db="Schiessbuch",
            cursorclass=MySQLdb.cursors.DictCursor)
            return conn
        finally:
            conn.close
bei den anderen execute habe ich ein %s drin stehen.

das %d ist doch für Zahlen. Oder immer noch Holzweg?
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Ach eben!!!

Du meintest das % hinter dem String? vor (Card_ID) jetzt habe ich das gesehen.

Code: Alles auswählen

def benutzer_registriert(db, user_id):
    print()
    with closing(db.cursor()) as cursor:
        cursor.execute("""SELECT tbl_Schiesstand.UserID
                        FROM tbl_Schiesstand
                        Where  tbl_Schiesstand.UserID = %s AND  tbl_Schiesstand.Ende IS NULL""", (user_id,))
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Ich frage mich ja immer noch, wie ich das ganze dann auf eine Grafische Oberfläche bekomme....

Wenn es mal einigermaßen geht.....
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: Auch hier hat der Ausdruck im ``finally``-Zweig keinen Effekt. Das gehört da ja auch überhaupt nicht hin. Das ist ja die Funktion in der die Verbindung aufgebaut wird. Die dort in einem ``finally`` gleich wieder zu schliessen wäre unsinnig.

Für eine grafische Oberfläche ist bei einigen Funktionen die Trennung zwischen Programmlogik und Benutzerinteraktion noch nicht sauber genug. `benutzer_anzeigen()` beispielsweise hat ja die Abfrage und die Ausgabe der Daten in einer Funktion. Die Abfrage wäre auch für eine GUI die gleiche, aber der Teil zum Anzeigen läuft dort anders.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

__blackjack__ hat geschrieben: Mittwoch 20. März 2019, 16:10 @matze1708: Auch hier hat der Ausdruck im ``finally``-Zweig keinen Effekt. Das gehört da ja auch überhaupt nicht hin. Das ist ja die Funktion in der die Verbindung aufgebaut wird. Die dort in einem ``finally`` gleich wieder zu schliessen wäre unsinnig.
Wo muss das dann stehen?
__blackjack__ hat geschrieben: Mittwoch 20. März 2019, 16:10 Für eine grafische Oberfläche ist bei einigen Funktionen die Trennung zwischen Programmlogik und Benutzerinteraktion noch nicht sauber genug. `benutzer_anzeigen()` beispielsweise hat ja die Abfrage und die Ausgabe der Daten in einer Funktion. Die Abfrage wäre auch für eine GUI die gleiche, aber der Teil zum Anzeigen läuft dort anders.
Wie muss diese Funktion dann getrennt sein? Quasi das Ergbniss der Abfrage an eine andere Funktion übergeben und von dieser dann die Anzeige gestalten?
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Was für mich auch noch interessant wäre, ich würde gerne den User Input soweit einschränken das er nur die Wahl hat zwischen den angezeigten Möglichkeiten.
Bsp Kaliber... dann soll er nur die Auswahl haben, von dem was gezeigt wird.
Oder bei Platz. da müsste ich vor selektireren welche Plätze auf dem aktuellen Stand belegt sind.
auf der GUI würde ich dafür Buttons nehmen und die dann ausblenden oder sperren die belegt sind.

Lässt sich das jetzt hier schon mit den vorhandnen eingaben machen?
Die Stand Rückgabe müsste ich sicherlich als Tupel machen?! in der Funktion dann Return XXX
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: Das schliessen der Datenbankverbindung muss da stehen wo Du weisst das Du sie nicht mehr brauchst. Und wenn man ``with`` verwendet, üblicherweise in der Funktion/Methode in der die Verbindung auch hergestellt wird. Du hattest es ja dort bereits in einem ``finally`` stehen.

Die Abfrage der Benutzerdaten von der Datenbank wäre eine eigene Funktion. Denn das ist ja der Teil der bei Terminal und GUI gleich bleibt. Die Anzeige selbst ist unterschiedlich. Beim Terminal verwendet man ``print()`` dafür. Bei einer GUI könnte man die Daten beispielsweise in einem Drop-Down-Menü zur Auswahl zur Verfügung stellen.

Wenn Du die Benutzereingabe auf gültige Werte einschränken möchtest, müsstest Du Funktionen bereit stellen die Dir die Möglichkeiten von der Datenbank abfragen und entsprechen die Eingabe überprüfen. Du machst das ja jetzt bereits zum Teil, nämlich ob die Eingabe eine Zahl ist. Da muss dann noch dazu kommen ob es eine Zahl aus einer Menge von vorgegebenen Zahlen ist. Und die bekommst Du ja mit der Abfrage der Kaliber.

Bei den Rückgaben von den Funktionen kannst Du Listen mit den Datenbankergebnissen zurück geben, oder Du fängst an hier zwischen der Datenhaltung und Objekten im Programm zu trennen und die Ergebnisse ”umzupacken”, beispielsweise in `collections.namedtuple` oder Klassen, damit das alles mehr nach Python aussieht und man nicht die Wörterbücher mit den unpytonischen Schlüsselnamen von der Datenbank hat. Alternativ könnte man die Spaltennamen in der Datenbank an die Python-Konventionen anpassen und die Ergebnisse in `addict.Dict`-Objekte verpacken. Oder sich mit dem SQLAlchemy-ORM beschäftigen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

__blackjack__ hat geschrieben: Donnerstag 21. März 2019, 10:30 @matze1708: Das schliessen der Datenbankverbindung muss da stehen wo Du weisst das Du sie nicht mehr brauchst. Und wenn man ``with`` verwendet, üblicherweise in der Funktion/Methode in der die Verbindung auch hergestellt wird. Du hattest es ja dort bereits in einem ``finally`` stehen.
Das wäre doch dann am Ende der main() weil, da ab da brauche ich es ja nicht mehr. Bis sich ein User neu anmeldet.
__blackjack__ hat geschrieben: Donnerstag 21. März 2019, 10:30 Die Abfrage der Benutzerdaten von der Datenbank wäre eine eigene Funktion. Denn das ist ja der Teil der bei Terminal und GUI gleich bleibt. Die Anzeige selbst ist unterschiedlich. Beim Terminal verwendet man ``print()`` dafür. Bei einer GUI könnte man die Daten beispielsweise in einem Drop-Down-Menü zur Auswahl zur Verfügung stellen.
Also muss ich das Ergebnis aus

Code: Alles auswählen

def kaliber_anzeigen(db, stand_id):
    print()
    with closing(db.cursor()) as cursor:
        cursor.execute("""Select tbl_Kaliber.ID, tbl_Kaliber.KaliberLang
            From tbl_Stand INNER JOIN tbl_Kaliber ON tbl_Stand.ID = tbl_Kaliber.StandID
            Where tbl_Stand.ID = %s""", (stand_id,))
        for row in cursor:
            print( row["ID"], row["KaliberLang"])
sprich den Cursor execute in eine Variable schreiben und die weiterverwenden in der Anzeige. Oder reicht das ab dem Bereich for row etc.
__blackjack__ hat geschrieben: Donnerstag 21. März 2019, 10:30 Wenn Du die Benutzereingabe auf gültige Werte einschränken möchtest, müsstest Du Funktionen bereit stellen die Dir die Möglichkeiten von der Datenbank abfragen und entsprechen die Eingabe überprüfen. Du machst das ja jetzt bereits zum Teil, nämlich ob die Eingabe eine Zahl ist. Da muss dann noch dazu kommen ob es eine Zahl aus einer Menge von vorgegebenen Zahlen ist. Und die bekommst Du ja mit der Abfrage der Kaliber.
Genau diese Menge an Zahlen muss ich verarbeiten. Diese Frage stelle ich mir gerade.
Habe dazu erstmal die tbl_Stand erweitert mit der Maximalen Anzahl der Plätze. Somit kann niemand Platz 30 eingeben wenn es nur 20 gibt.
Dann hatte ich übeleget über ein SELECT zu schauen welche Plätze aktuell belegt sind. Das kann ich ja ausgeben über for row, aber ich muss das ja dann in eine Variable packen oder? Die row´s sind ja Vertikal und die Variable müsste ja Horizontal sein. Da habe ich noch nix zu gefunden wie ich das "drehe"
__blackjack__ hat geschrieben: Donnerstag 21. März 2019, 10:30
Bei den Rückgaben von den Funktionen kannst Du Listen mit den Datenbankergebnissen zurück geben, oder Du fängst an hier zwischen der Datenhaltung und Objekten im Programm zu trennen und die Ergebnisse ”umzupacken”, beispielsweise in `collections.namedtuple` oder Klassen, damit das alles mehr nach Python aussieht und man nicht die Wörterbücher mit den unpytonischen Schlüsselnamen von der Datenbank hat. Alternativ könnte man die Spaltennamen in der Datenbank an die Python-Konventionen anpassen und die Ergebnisse in `addict.Dict`-Objekte verpacken. Oder sich mit dem SQLAlchemy-ORM beschäftigen.
Ok hier erklärst du das ich das auf Listen Element umsetzten kann.

Aber was mache ich mit diesem colections.namedtuple? Für das addict.Dict fällt mir gerade noch der Verstand.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Ich habe da mal weiter gespielt:

Code: Alles auswählen

def freierPlatz(db, stand_id):
    with closing(db.cursor()) as cursor:
        cursor.execute("""SELECT Platz FROM tbl_Schiesstand WHERE Ende is Null And StandID =%s """, (stand_id))
        return list(cursor)
Würde mir jetzt rein vom SQL die Plätze ausgeben die belegt sind.

nur das list(Cursor) ist mir nicht so recht.

Da kommt dann sowas raus:
Traceback (most recent call last):
File "schuetzeanlegen.py", line 208, in <module>
main()
File "schuetzeanlegen.py", line 191, in main
print(freierPlatz(db, stand_id))
File "schuetzeanlegen.py", line 95, in freierPlatz
cursor.execute("""SELECT Platz FROM tbl_Schiesstand WHERE Ende is Null And StandID =%s """, (stand_id))
File "/usr/local/lib/python3.5/dist-packages/MySQLdb/cursors.py", line 199, in execute
args = tuple(map(db.literal, args))
TypeError: 'int' object is not iterable
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: `collections.namedtuple` oder `addict.Dict` wären dazu da um aus Wörterbüchern mit festen Schlüsseln (Anzahl und Wert) Werte zu machen die eigene Datentypen mit Attributen und in Python üblicher Namensgebung sind. `Dict` wäre da eher ”Kosmetik”/syntaktischer Zucker und man müsste auch die Datenbankfelder umbenennen, damit das funktioniert/Sinn macht. Im Moment hantierst Du mit Wörterbüchern die feste Datensätze darstellen. Das ist eigentlich nicht der Einsatzzweck für Wörterbücher. Die verwendet man eher wenn die Anzahl der Schlüssel/Wert-Paare dynamisch sind, und alle im Grunde die gleiche Bedeutung haben. Als Datensätze eigentlich nur für Zwischenergebnisse an den ”Rändern” des Programms, wo die Daten das Programm betreten oder verlassen. Also hier zum Beispiel das sie in der Form das Programm über die Datenbankabfrage betreten.

Du musst keine Variablen ”drehen” sondern Teile aus einer Sequenz in eine neue Sequenz oder Menge heraus ziehen. Du hast ja beim Kaliber für die Auswahl beispielsweise Paare von IDs und Beschreibung zur ID und brauchst nur die IDs. Ich weiss jetzt nicht was Du denkst was Du da suchst, aber das ist eine Schleife über die Paare in der man sich dann die IDs nimmt und in einer anderen Datenstruktur speichert. Entweder tatsächlich eine Schleife oder eine „list comprehension“ oder „set comprehension“.

Warum ist Dir das `list()` nicht recht? An der Stelle könnte man natürlich schon die Platznummern aus den Wörterbüchern holen die ja jeweils nur ein Element enthalten. Versuch Dich bei den Rückgabewerten schon mal so ein bisschen von der Datenbank zu trennen und zu überlegen was denn Deine Programmlogik da eigentlich braucht. Das wäre eine Sequenz oder Menge von freien Platznummern. Die sollte man dann auch liefern und nicht dem Aufrufer das Auspacken aus den Wörterbüchern aufbürden.

Der Funktionsname entspricht übrigens nicht den Konventionen. Schreibweise wäre `freier_platz`. Und inhaltlich sollten Namen für Funktionen und Methoden eine Tätigkeit beschreiben, also `hole_freien_platz()`. Das holt aber gar nicht die freien Plätze sondern die belegten. Und *Plätze* – Mehrzahl. Also `hole_belegte_plaetze()`. Ich würde auch noch so pedantisch sein und `hole_belegte_platznummern()` schreiben, damit klar ist, das es sich bei den Plätzen um Nummern handelt und nicht um komplexere Objekte die jeweils einen Platz beschreiben. Also *eigentlich* auch in Englisch – `get_occupied_place_numbers()`.

Code: Alles auswählen

def get_occupied_place_numbers(db, range_id):
    with closing(db.cursor()) as cursor:
        cursor.execute(
            'SELECT Platz FROM tbl_Schiesstand'
            ' WHERE Ende IS NULL AND StandID = %s',
            (range_id,)
        )
        return [row['Platz'] for row in cursor]
Die Ausnahme bekommst Du weil Du das Komma beim zweiten Argument von `execute()` vergessen hast, damit das ein Tupel wird und nicht einfach nur eine Zahl ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Warum ist Dir das `list()` nicht recht? An der Stelle könnte man natürlich schon die Platznummern aus den Wörterbüchern holen die ja jeweils nur ein Element enthalten. Versuch Dich bei den Rückgabewerten schon mal so ein bisschen von der Datenbank zu trennen und zu überlegen was denn Deine Programmlogik da eigentlich braucht. Das wäre eine Sequenz oder Menge von freien Platznummern. Die sollte man dann auch liefern und nicht dem Aufrufer das Auspacken aus den Wörterbüchern aufbürden.
Weil ich wahrscheinlich das falsche dazu gefunden habe und es dann auch noch falsch zusammen gebaut habe.... :-(

Ich müsste das doch dann umrechnen, um noch die freien Plätze zu bekommen.

Gut ich könnte ja mit dieser Info auf einer GUI dann die belegten Plätze ausblenden. Wenn ich mir vorstelle, dass ich Buttons dynamisch darstelle.

Aber es wäre dennoch interessant zu wissen wie ich von der Maximalen Anzahl und der bereits belegten Plätze auf alle freien Plätze komme.
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: Du zählst halt alle Plätze auf und lässt die bereits belegten aus.

Code: Alles auswählen

    occupied_place_numbers = set(get_occupied_place_numbers(db, range_id))
    max_place_number = get_max_place_number(db, range_id)
    free_place_numbers = [
        place_number
        for place_number in range(1, max_place_number + 1)
        if place_number not in occupied_place_numbers
    ]
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten