Java týden Body zdarma
Využij podzimních slev a získej od nás až 40 % bodů zdarma! Více zde
Pouze tento týden sleva až 80 % na Java e-learning!

Lekce 5 - Uložení objektů do CSV v Pythonu část 2

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Uložení objektů do CSV v Pythonu, jsme načali databázi uživatelů pomocí CSV souborů. Nyní aplikaci dokončíme a doladíme.

Načtení uživatelů z CSV souboru

Uložení nám funguje, zbývá umět data opětovně načíst. Načteme všechny řádky ze souboru a každý řádek rozdělíme metodou split() a následně do seznamu přidáme objekt s příslušnými hodnotami. Před načtením si seznam vyprázdníme, aby v něm nebyli i uživatelé načtení někdy dříve (kdyby se aplikace někdy rozšiřovala).

def nacti(self):
    self.uzivatele = []
    with open(self.soubor, "r", encoding="utf-8") as f:
        for s in f.readlines():
            jmeno, vek, registrovan = s.strip().split(";")
            registrovan = datetime.datetime.strptime(registrovan, "%d.%m.%Y")
            self.pridejUzivatele(jmeno, vek, registrovan)

Třída Databaze je tedy kompletní. Nyní se zaměříme na formulářovou část.

Prezentační vrstva aplikace

Jako první si připravíme nové formulářové prvky. Aplikace je napsaná v tkinter, který je již součást Pythonu. Na vytvoření formuláře jsem použil pygubu-designer, který nainstalujete pomocí pip install pygubu a spustíte příkazem pygubu-designer. V pygubu-designeru si naklikáme formulář, který poté propojíme s funkcemi. Formulář je uložen jako XML v .ui souboru.

Návrh Python formuláře v pygubu-designer

Funkci, která se zavolá po kliknutí na tlačítko, v pygubu-designeru nastavíme po vybrání tlačítka v záložce General -> Specific -> command.

Command v pygubu designeru pro Python

Funkci, která se zavolá po vybrání položky z ListBoxu, v pygubu-designeru po vybrání ListBoxu nastavíme v záložce Bindings.

Bindings v pygubu designeru pro Python
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!

Přidáme tlačítko "Načíst", dále ListBox listUzivatelu. Dále Entry na jméno nového uživatele, Entry na jeho věk a Entry na datum registrace. K ovládacím prvkům přidáme nějaké labely. Tyto prvky můžeme seskupit do Frame. V dalším Frame budou 3 labely na detail uživatele, ty pojmenujeme jmenoLabel, vekLabel a registrovanLabel. Další 3 labely přidáme jako jejich popisek. Nakonec přidáme tlačítko "Přidat" k přidání uživatele. Pokud to bylo moc rychlé, zde je obrázek výsledného formuláře:

Formulář programu pro práci s CSV soubory v Pythonu

V reálu by bylo přidání uživatelů pravděpodobně přítomné v samostatném formuláři, který by se zobrazoval jako dialog, ale nám to bude v tutoriálu stačit takto.

Nejdříve si musíme upravit třídu Aplikace, abychom využili náš naklikaný formulář (zdrojové kódy a gui.iu jsou případně ke stažení na konci článku, kdyby vám cokoli nešlo). Formulář získáme načtením souboru, poté nastavíme rodiče hlavnímu framu a nakonec napojíme obslužné funkce. To vše za nás v pozadí provede pygubu a my se tak o nic nestaráme. Třída Aplikace nyní vypadá takto:

class Aplikace():

    def __init__(self, master):
        self.master = master
        self.db = Databaze("uzivatele.csv")
        self.builder = pygubu.Builder()
        self.builder.add_from_file("gui.ui")
        self.builder.get_object("Frame_1", self.master)
        self.builder.connect_callbacks(self)

A inicializujeme ji takto:

root = tkinter.Tk()
aplikace = Aplikace(root)
root.mainloop()

Z obsluhy tlačítka "Uložit" odstraníme vytvoření testovacích uživatelů. Samotné uložení nyní vložíme do try-except bloku. Víme totiž, že finally (tedy with blok v naší databázi) výjimky nepohlcuje, což také chceme a budeme na ně reagovat ve formulářové části, kam reakce logicky patří. Upozornění na chybu, tedy komunikace s uživatelem, přímo ve třídě Databaze by bylo špatně. Po zachycení výjimky zobrazíme MessageBox s chybou. Obslužná metoda tlačítka bude tedy vypadat takto:

def tlacitkoNacistClicked(self):
    try:
        self.db.uloz()
    except:
        messagebox.showerror("Chyba", "Databázi se nepodařilo uložit, zkontrolujte přístupová práva k souboru.")

Obdobně upravíme metodu tlačítka "Načíst", pouze po načtení databáze vložíme objekty do ListBoxu. Ten předtím vyprázdníme, aby nám tam nezůstávali uživatelé z předešlého načtení. V reálu by se načtení vykonalo asi automaticky po spuštění aplikace a uložení po ukončení, pro názornost si to však ponecháme na tlačítkách. Metoda tlačítka "Načíst" tedy vypadá takto:

def tlacitkoNacistClicked(self):
    try:
        self.db.nacti()
    except:
        messagebox.showerror("Chyba", "Databázi se nepodařilo načíst, soubor zřejmě neexisituje.")
        return
    listbox = self.builder.get_object("listUzivatelu")
    listbox.delete(0,tkinter.END)
    for u in self.db.VratVsechny():
        listbox.insert(tkinter.END, u.jmeno)

Nyní zpracujeme kliknutí na položku v listUzivatelu, které provede zobrazení detailu vybraného uživatele do připravených labelů:

def ziskejUzivatele(self, evt):
    listbox = self.builder.get_object("listUzivatelu")
    i = listbox.curselection()[0] + 1 if len(listbox.curselection()) > 0 else None
    if len(self.db.uzivatele) == 0 or i == None:
        return
    jmeno_label = self.builder.get_object("jmenoLabel")
    vek_label = self.builder.get_object("vekLabel")
    registovan_label = self.builder.get_object("registrovanLabel")
    u = self.db.uzivatele[i-1]
    jmeno_label["text"] = u.jmeno
    vek_label["text"] = u.vek
    registovan_label["text"] = u.registrovan.strftime("%d.%m.%Y")

Kód jsme opodmínkovali pro případ, že by nebyl žádný uživatel vybrán (list by byl prázdný). Můžete si vyzkoušet, že vše funguje.

Poslední tlačítko bez metody je "Přidat" nového uživatele. Vytvoříme si obslužnou metodu. Vložení bude velmi jednoduché, prvek ovšem musíme přidat jak do databáze, tak do listUzivatelu:

def tlacitkoPridatClicked(self):
    jmeno = self.builder.get_object("jmenoEntry").get()
    vek = self.builder.get_object("vekEntry").get()
    registrovan = self.builder.get_object("registrovanEntry").get()
    if jmeno == "" or vek == "" or registrovan == "":
        return
    registrovan = datetime.datetime.strptime(registrovan, "%d.%m.%Y")
    self.db.pridejUzivatele(jmeno, vek, registrovan)
    listbox = self.builder.get_object("listUzivatelu")
    listbox.delete(0,tkinter.END)
    for u in self.db.vratVsechny():
        listbox.insert(tkinter.END, u.jmeno)

Zkusíme přidat nového uživatele:

Přidání nového uživatele v CSV databázi v Pythonu

Podobně bychom si mohli napsat i mazání uživatelů, ale to již nechám na vás. Zbývá nám ještě ošetřit cestu k souboru, aby vedla do složky AppData, nikoli do složky s programem. To umíme z tutoriálu Úvod do práce se soubory v Pythonu. Získání cesty vykonáme v konstruktoru třídy Aplikace:

def __init__(self, master):
    self.master = master
    try:
        cesta = os.path.join(os.getenv("APPDATA"), "DatabazeUzivatelu")
        if not os.path.exists(cesta):
            os.mkdir(cesta)
    except:
        messagebox.showerror("Chyba", "Nepodařilo se vytvořit složku " + cesta + ", zkontrolujte prosím svá oprávnění.")
    self.db = Databaze(os.path.join(cesta, "uzivatele.csv"))
    self.builder = pygubu.Builder()
    self.builder.add_from_file("gui.ui")
    self.builder.get_object("Frame_1", self.master)
    self.builder.connect_callbacks(self)

A je to :)

Naše aplikace je téměř hotová, ještě se zamyslíme nad tím, co se stane, když někdo do jména vloží středník. Aplikace se rozbije. Proto budeme v metodě uloz() středníky ze jména odstraňovat. Kdybychom dělali aplikaci, kde bychom je potřebovali (což se nestává příliš často), můžeme vybrat jiný zástupný znak. Pokud bychom chtěli být dokonalí, vložíme takovou hodnotu se středníkem do uvozovek. Poté se však již nejedná o jednoduché CSV a metoda split() nám přestane stačit. Dále by se to samozřejmě dalo řešit jiným formátem. My si tedy středníky pouze odstraňme, přesněji je nahradíme mezerami změnou jediného řádku v metodě uloz():

hodnoty = [u.jmeno.replace(";", " "), str(u.vek), u.registrovan.strftime("%d.%m.%Y")]

A jsme hotoví. Pokud vám něco nešlo úplně hladce, hotový projekt máte jako vždy v příloze i se zdrojovým kódem. V příští lekci, Úvod do formátu XML v Pythonu, se podíváme na formát XML.


 

Stáhnout

Staženo 29x (3.12 kB)
Aplikace je včetně zdrojových kódů v jazyce Python

 

 

Aktivity (6)

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!