tkinter.combobox und Foreign Key

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
guhamail
User
Beiträge: 22
Registriert: Samstag 19. Februar 2022, 13:34
Wohnort: Brandenburg

Hallo,

ich bin dabei ein wenig mit tkinter und sqlite rumzuspielen. Das Ganze erfüllt nur den Zweck des dazu lernens, also kein produktiver Einsatz.

Ich habe eine Datenbank mit den folgenden Tabellen angelegt:

Code: Alles auswählen

c.execute('''
CREATE TABLE IF NOT EXISTS genders (
    gender_id INTEGER PRIMARY KEY,
    gender_name TEXT NOT NULL
)
''')

c.execute('''
CREATE TABLE IF NOT EXISTS names (
    name_id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    gender_id INTEGER,
    FOREIGN KEY (gender_id) REFERENCES genders (gender_id)
)
''')

c.execute("INSERT OR IGNORE INTO genders (gender_id, gender_name) VALUES (1, 'Male')")
c.execute("INSERT OR IGNORE INTO genders (gender_id, gender_name) VALUES (2, 'Female')")
c.execute("INSERT OR IGNORE INTO genders (gender_id, gender_name) VALUES (3, 'Other')")

Jetzt möchte ich mit tkinter ein Formular bauen, um die Tabelle names mit Daten zu befüllen. Für gender möchte ich eine Combobox verwenden, welche die Werte gender_name aus der Tabelle genders enthält. Wenn ich einen neuen Datensatz in names speichern möchte, benötige ich allerdings die gender_id und nicht gender_name.

Mir fehlt grad eine Idee, wie ich das hinbekomme. Könnt ihr mir weiter helfen?
Benutzeravatar
__blackjack__
User
Beiträge: 13997
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@guhamail: Erstell ein Wörterbuch das den Namen auf die ID abbildet. Dann kannst Du da einfach nachschauen.

Zu den SQL-Namen: Die Tabellennamen sollten eher in der Einzahl sein, also `gender` und `name`, denn das ist so ähnlich wie eine Klassendefinition, da wird *ein* Datensatz beschrieben.

Den Tabellennamen sollte man nicht noch mal in den Attributen wiederholen. Also `genders.gender_id` und `genders.gender_name` sollte eher `gender.id` und `gender.name` sein, und `names.name_id` eher `name.id` sein. Es macht keinen Sinn diese Information zu wiederholen.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
guhamail
User
Beiträge: 22
Registriert: Samstag 19. Februar 2022, 13:34
Wohnort: Brandenburg

Vielen Dank für die Hinweise. Habe ich gleich umgesetzt.

Ich habe mir auch eine Lösung überlegt:

Ich ziehe mir alle Datensätze von der Tabelle gender in eine Variable

Code: Alles auswählen

c.execute("SELECT  * FROM gender")
gender = c.fetchall()
beim Absenden des tkinter-Formulars ermittle ich, welcher Index in der gender-Combobox vom User ausgewählt wurde

Code: Alles auswählen

selected_index = gender_combobox.current()
mit diesem Index ziehe ich mir die id aus der Variable gender

Code: Alles auswählen

gender_id = gender[selected_index][0]
Mit dieser id kann ich die Speicherung in der Datenbank vornehmen.

Ist meine Lösung zu laienhaft??
Benutzeravatar
__blackjack__
User
Beiträge: 13997
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@guhamail: Das ist halt ein bisschen indirekt und undurchsichtig mit dem Sternchen und der magischen 0 wo man nicht weiss was da selektiert wird ohne die Tabellendefinition zu schauen. Und es hat das kleine Problem, dass das auch ”funktioniert” wenn man gar nichts ausgewählt hat, weil -1 auch ein gültiger Index ist.

Man kann bei der `Combobox` ja ein `StringVar`-Objekt verwenden. Ungetestet:

Code: Alles auswählen

    cursor.execute("SELECT name, id FROM gender")
    gender_name_to_id = dict(cursor.fetchall())

    ...

    gender_name = gender_name_var.get()
    if gender_name:
        gender_id = gender_name_to_id[gender_name]
        # do something with gender_id
Edit: Bei `gender.name` in der Datenbank würde es sich anbieten ein UNIQUE-Constraint anzugeben.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Antworten