CSV Datei beschreiben

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.
Antworten
HoLaHe
User
Beiträge: 15
Registriert: Montag 11. Juli 2022, 07:46

Ich habe ein Problem mit dem beschreiben einer CSV Datei. Ich öffnet die Datei schon mit "file = open("Knotenzuordnung.csv", "a")" aber es wird nicht hinzugefügt sodern überschrieben.
Meinen def lautet so:

Code: Alles auswählen

 data = (entry_street.get()), ",", (entry_number.get()), ",", (entry_customer.get()), ",", (entry_node.get()), "\n",
    toWrite = [data]
    file = open("Knotenzuordnung.csv", "a")
Was mach ich falsch?
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

`a` ist schon ok - zeigt mal bitte den kompletten relevanten Code. Im gezeigten ist der Schreibvorgang nicht zu sehen.

Allgemein: Dateien öffnet man besser mit dem `with` Statement, dann kümmert sich Python selber um's Schließen der Datei. Für CSV-Dateien gibt es ein csv-Modul, das Python standardmäßig an Bord hat.

Die ersten beiden Zeilen im gezeigten Code sind... komisch. Warum erzeugst du erst ein Tupel und packst es dann in eine 1-elementige Liste? Variablennamen schreibt man in Python per Konvention klein_mit_Unterstrich, also `to_write`.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@HoLaHe: Zu viele unnötige Klammern, man muss nicht jedes Zwischenergebnis an einen Namen binden, die meisten Namen werden in Python klein_mit_unterstrichen geschrieben, keiner in camelCase, Dateien sollte man wenn möglich mit der ``with``-Anweisung zusammen öffnen, bei Textdateien die Kodierung angeben, zum schreiben von CSV-Date(ie)n gibt es das `csv`-Modul in der Standardbibliothek, und Du zeigst hier weder wie Du schreibst, noch dass die Datei wieder geschlossen wird.

Edit: Ungetestet:

Code: Alles auswählen

    with open(
        "Knotenzuordnung.csv", "a", newline="", encoding="utf-8"
    ) as file:
        csv.writer(file).writerow(
            [
                item.get()
                for item in [
                    entry_street,
                    entry_number,
                    entry_customer,
                    entry_node,
                ]
            ]
        )
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
HoLaHe
User
Beiträge: 15
Registriert: Montag 11. Juli 2022, 07:46

@__blackjack__ vielen Dank für die Erklärung.

ich hab es mit dem with Open.. probiert, allerdings überschreibt es trotzdem die Daten. die mal der komplette Code. Vermutlich schlagt ihr beide Hände über dem Kopf zusammen :o , aber ich bin noch Anfänger in Sachen python. Also seid nicht zu böse nit mir :wink: :cry:

Code: Alles auswählen

#!/usr/bin/python
#-*- coding: utf-8 -*-

# Import the required libraries
import tkinter as tk
from tkinter import ttk
from tkinter.ttk import Label
from tkinter import Listbox
from tkinter import Text
from tkinter.ttk import Combobox
from tkinter import *
from tkinter.ttk import *
import csv
import pandas

# Create an instance of tkinter frame or window
root = tk.Tk()

# Set the size an the Title of the window
root.geometry('900x320')
root.title('Adressbuch Knotenzuweisung')

p1 = PhotoImage(file = '957980.png')
root.iconphoto(False, p1)

var=IntVar()

def search():
    text.delete("1.0","end")
    choice = var.get()
    if choice == 1:
        output = "Strasse"

    elif choice == 2:
        output = "Kunde"

    elif choice == 3:
        output = "Knoten"
    else:
        output = "Invalid selection"
    sd = pandas.read_csv('Knotenzuordnung.csv')
    res_sd = sd.query(f'{output} == "{entry_search.get()}"')
    text.insert(END, f"{res_sd}")

def delete_search():
    entry_search.delete(0, tk.END)

def delete_all():
    entry_street.delete(0, tk.END)
    entry_number.delete(0, tk.END)
    entry_customer.delete(0, tk.END)
    entry_node.delete(0, tk.END)
    entry_notice.delete(0, tk.END)

def save():
    with open(
        "Knotenzuordnung.csv", "a", newline="", encoding="utf-8"
    ) as file:
        csv.writer(file).writerow(
            [
                item.get()
                for item in [
                    entry_street,
                    entry_number,
                    entry_customer,
                    entry_node,
                ]
            ]
        )

# Define a function to get the output for selected option
def viewSelected():
    choice = var.get()
    if choice == 1:
        output = "Strasse"

    elif choice == 2:
        output = "Kunde"

    elif choice == 3:
        output = "Knoten"
    else:
        output = "Invalid selection"

# show labels
label_street = Label(root, text='Neue Daten eintragen :  ', font=('times', 14, 'bold'))
label_street.place(x=10, y=10)

label_street = Label(root, text='Neue Suche starten :  ', font=('times', 14, 'bold'))
label_street.place(x=400, y=10)

label_street = Label(root, text='Strasse : ')
label_street.place(x=10, y=40)

label_number = Label(root, text='Hausnummer : ')
label_number.place(x=10, y=80)

label_customer = Label(root, text='Kunde : ')
label_customer.place(x=10, y=120)

label_node = Label(root, text='Knotennummer : ')
label_node.place(x=10, y=160)

label_notice = Label(root, text='Bemerkung : ')
label_notice.place(x=10, y=200)

label_search = Label(root, text='Suche nach : ')
label_search.place(x=400, y=40)

label_output = Label(root, text='Ausgabe : ', font=('times', 14, 'bold'))
label_output.place(x=400, y=140)

# show entrys
entry_street= ttk.Entry(root, width=40)
entry_street.place(x=110, y=40)

entry_number= ttk.Entry(root, width=40)
entry_number.place(x=110, y=80)

entry_customer= ttk.Entry(root, width=40)
entry_customer.place(x=110, y=120)

entry_node= ttk.Entry(root, width=40)
entry_node.place(x=110, y=160)

entry_notice= ttk.Entry(root, width=40)
entry_notice.place(x=110, y=200)

entry_search= ttk.Entry(root, width=40)
entry_search.place(x=480, y=40)

# show buttons
button_write = ttk.Button(root, text="Speichern", command=save)
button_write.place(x=120 , y=240)

#button_overwride = ttk.Button(root, text="Ändern", command=search)
#button_overwride.place(x=100 , y=340)

button_write = ttk.Button(root, text="Eingaben zurücksetzen", command=delete_all)
button_write.place(x=225 , y=240)

button_search = ttk.Button(root, text="Suchen", command=search)
button_search.place(x=480 , y=100)

button_delete_search = ttk.Button(root, text="Eingabe löschen", command=delete_search)
button_delete_search.place(x=580 , y=100)

# configure Radio Buttons
radio_street = Radiobutton(root, text="Strasse", variable=var, value=1, command=viewSelected)
radio_street.place(x=480 , y=70)
radio_customer = Radiobutton(root, text="Kunde", variable=var, value=2, command=viewSelected)
radio_customer.place(x=550 , y=70)
#radio_node = Radiobutton(root, text="Knoten", variable=var, value=3, command=viewSelected)
#radio_node.place(x=680 , y=60)

text=Text (root, width=60, height=5)
text.place (x=400, y=180)
#text.insert(END, f"test {res_sd}")


root.mainloop()
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Anfänger machen Fehler, weil ihnen noch niemand gezeigt hat, wie es richtig geht. Wenn man sie nicht auf Fehler hinweist, können sie ja nicht besser werden.
Die Importe sind wirr. *-Importe benutzt man nicht, weil sie verschleiern, woher welcher Name kommt. Der Kommentar ist überflüssig, weil man ja am ›import‹ erkennt, dass es sich um Importe handelt. Alle Importe sind notwendig, weil nicht-notwendige würde man löschen.
Man benutzt keine globalen Variablen, alle Informationen müssen den Funktionen über Argumente übergeben werden.
Man darf keine absoluten Größen angeben, weil das je nach System die GUI unbenutzbar macht. Bei mir überschneiden sich die GUI-Elemente zum Beispiel.
Sehr verwirrend ist, dass drei Label `label_street` heißen, oder der Button zum Zurücksetzen gleich, wie der zum Speichern.
Nicht alles braucht einen Variablennamen.
Die Label sollten in der Nähe der Textfelder stehen.
Warum verwendest Du für die Radiobuttons Zahlen, wo Du doch eigentlich Strings willst?

Code: Alles auswählen

#!/usr/bin/python
from functools import partial
import tkinter as tk
from tkinter import ttk
import csv
import pandas

def search(entry_search, var, text):
    text.delete("1.0","end")
    choice = var.get()
    sd = pandas.read_csv('Knotenzuordnung.csv')
    res_sd = sd.query(f'{output} == "{entry_search.get()}"')
    text.insert(END, f"{res_sd}")

def delete_search(entry_search):
    entry_search.delete(0, tk.END)

def delete_all(entries):
    for entry in entries:
        entry.delete(0, tk.END)

def save(entries):
    with open(
        "Knotenzuordnung.csv", "a", newline="", encoding="utf-8"
    ) as file:
        csv.writer(file).writerow(
            [
                entry.get()
                for entry in entries
            ]
        )

def main():
    root = tk.Tk()
    root.title('Adressbuch Knotenzuweisung')
    
    left_frame = tk.Frame(root)
    left_frame.grid(row=0, column=0, sticky=tk.NW)
    tk.Label(left_frame, text='Neue Daten eintragen :  ',
        font=('times', 14, 'bold')
    ).grid(row=0, column=0, columnspan=2, sticky=tk.NW)

    tk.Label(left_frame, text='Strasse:').grid(row=1, column=0, sticky=tk.NW)
    entry_street = ttk.Entry(left_frame, width=40)
    entry_street.grid(row=1, column=1)

    tk.Label(left_frame, text='Hausnummer:').grid(row=2, column=0, sticky=tk.NW)
    entry_number = ttk.Entry(left_frame, width=40)
    entry_number.grid(row=2, column=1, sticky=tk.NW)

    tk.Label(left_frame, text='Kunde:').grid(row=3, column=0, sticky=tk.NW)
    entry_customer = ttk.Entry(left_frame, width=40)
    entry_customer.grid(row=3, column=1, sticky=tk.NW)

    tk.Label(left_frame, text='Knotennummer:').grid(row=4, column=0, sticky=tk.NW)
    entry_node = ttk.Entry(left_frame, width=40)
    entry_node.grid(row=4, column=1, sticky=tk.NW)

    tk.Label(left_frame, text='Bemerkung:').grid(row=5, column=0, sticky=tk.NW)
    entry_notice = ttk.Entry(left_frame, width=40)
    entry_notice.grid(row=5, column=1, sticky=tk.NW)

    entries = [
        entry_street,
        entry_number,
        entry_customer,
        entry_node,
        entry_notice,
    ]

    frame = tk.Frame(left_frame)
    frame.grid(row=6, column=1, sticky=tk.NW)
    ttk.Button(frame, text="Speichern", command=partial(save, entries)).pack(side=tk.LEFT)
    ttk.Button(frame, text="Eingaben zurücksetzen", command=partial(delete_all, entries)).pack(side=tk.LEFT)

    right_frame = tk.Frame(root)
    right_frame.grid(row=0, column=1, sticky=tk.NW)
    tk.Label(right_frame, text='Neue Suche starten :  ',
        font=('times', 14, 'bold')
    ).grid(row=0, column=2, columnspan=2, sticky=tk.NW)

    tk.Label(right_frame, text='Suche nach : ').grid(row=1, column=2, sticky=tk.NW)
    entry_search = ttk.Entry(right_frame, width=40)
    entry_search.grid(row=1, column=3, sticky=tk.NW)

    frame = tk.Frame(right_frame)
    frame.grid(row=2, column=3, sticky=tk.NW)
    var = tk.StringVar(root)
    tk.Radiobutton(frame, text="Strasse", variable=var, value="Strasse").pack(side=tk.LEFT)
    tk.Radiobutton(frame, text="Kunde", variable=var, value="Kunde").pack(side=tk.LEFT)
    tk.Radiobutton(frame, text="Knoten", variable=var, value="Knoten").pack(side=tk.LEFT)

    tk.Label(right_frame, text='Ausgabe:',
        font=('times', 14, 'bold')).grid(row=4, column=2, columnspan=2, sticky=tk.NW)

    text = tk.Text(right_frame, width=60, height=5).grid(row=5, column=2, columnspan=2, sticky=tk.NW)

    frame = tk.Frame(right_frame)
    frame.grid(row=3, column=3, sticky=tk.NW)
    ttk.Button(frame, text="Suchen", command=partial(search, entry_search, var, text)).pack(side=tk.LEFT)
    ttk.Button(frame, text="Eingabe löschen", command=partial(delete_search, entry_search)).pack(side=tk.LEFT)


    root.mainloop()

if __name__ == "__main__":
    main()
Und bei mir werden keine Einträge in der Datei überschrieben. Warum glaubst Du, dass das passiert?
HoLaHe
User
Beiträge: 15
Registriert: Montag 11. Juli 2022, 07:46

@ Sirius3 vielen Dank für die Erklärung und das Aufräumen.

Nicht ganz klar ist mir dein Listeneintrag
entries = [
entry_street,
entry_number,
entry_customer,
entry_node,
entry_notice,
]



Wenn ich den von dir aufgeräumten Code ausführe und dann was suchen möchte bekomm ich eine Fehlermeldung:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3568.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
File "C:\Users\xyz\PycharmProjects\Knotenzuordnung\Main2.py", line 10, in search
text.delete("1.0", "end")
AttributeError: 'NoneType' object has no attribute 'delete'
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

`grid` hat halt als Rückgabewert None, deshalb muß man die Zeile in zwei aufspalten:

Code: Alles auswählen

text = tk.Text(right_frame, width=60, height=5)
text.grid(row=5, column=2, columnspan=2, sticky=tk.NW)
Da Du viele gleichartige Entry-Felder hast, ist es sinnvoll, diese in einer Liste zu sammeln.
HoLaHe
User
Beiträge: 15
Registriert: Montag 11. Juli 2022, 07:46

Ich habe noch eine Frage. Das script lüft jetz soweit. Wenn ich jetzt nach einer Straße suche z.B. Musterstraße muss ich in das Suchfeld auch genauso Musterstraße eintragen. Wie bekomm ich das hin das ich zB. nur Muster eingebe und er mir Trotzdem die Straße bzw wenn es mehrere Werte mit Muster gibt anzeigt?
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@HoLaHe: Du solltest als erstes mal den `query()`-Aufruf loswerden, weil da vom Benutzer eingegebener Code ausgeführt werden kann. Es geht hier ja um einfache Zeichenkettenoperationen. Im Original sogar nur um Test auf Gleichheit, da braucht man ganz sicher `query()` nicht für. Und auch für das was Du anscheinend jetzt möchtest, enthalten sein einer Teilzeichenkette, ist über die Methoden auf dem `str`-Attribut von `Series`-Objekten leicht machbar. Die Methode heisst `contains()` und verwendet per Voreinstellung schon reguläre Ausdrücke. Das kannst Du nutzen, also dem Benutzer auch so sagen/zur Verfügung stellen, oder durch das entsprechende Argument der Methode abschalten.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sowas nennt sich Auto-Completion, und dafuer gibt es ein Zusatzpaket, dass sowas anbietet: https://ttkwidgets.readthedocs.io/en/la ... Entry.html
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

__blackjack__ hat geschrieben: Freitag 9. September 2022, 12:15

Code: Alles auswählen

    with open(
        "Knotenzuordnung.csv", "a", newline="", encoding="utf-8"
    ) as file:
        csv.writer(file).writerow(
            [
                item.get()
                for item in [
                    entry_street,
                    entry_number,
                    entry_customer,
                    entry_node,
                ]
            ]
        )
Wobei das mit Zwischenergebnissen ein paar Zeilen weniger verbrauchen und der Code nicht wie ein Kunstprojekt aussehen würde. ;)
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Naja, die `entries` kommen ja letztlich eh besser als Liste von aussen:

Code: Alles auswählen

    with open(
        "Knotenzuordnung.csv", "a", newline="", encoding="utf-8"
    ) as file:
        csv.writer(file).writerow([item.get() for item in entries])
Ansonsten formatiert Black das halt so, und bevor ich da anfange rum zu probieren was man am besten wie raus zieht um möglichst wenige Zeilen zu haben, spare ich mir den Aufwand lieber. Ich finde das Kunstprojekt noch verständlich. Das kann man ”vorlesen”.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten