Datenbank Aufbau

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

Hab mich durch einen Beitrag dazu inspirieren lassen, etwas mit dictionaries und Datenbanken zu experimentieren.
Ein kleines Konstrukt ist dabei entstanden: (unvollständig)

Code: Alles auswählen

import csv

class Database():
    def __init__(self):
        pass

    def importDB(self, db_path):
        self.db_path = db_path
        self.database = {}
        with open(self.db_path, "r") as db:
            for key, value in csv.reader(db):
                self.database[key] = value

    def appendUser(self, userdata):
        username = "{}{}".format("Customer_", len(self.database.keys())+1)
        a, b, c, d, e, f, g, h, i, j = userdata
        self.database[username] = {'Bezeichnung':a, 'Strasse':b, 'Postleitzahl':c,
                                   'Ort':d, 'Land':e, 'Tuer':f, 'Treppe':g, 'Telefon':h,
                                   'Fax':i, 'Postfach':j}

    def delUser(self, usr):
        #search through database and delete user
        pass

    def getUser(self, usr):
        #return userdata
        return eval(self.database[usr])

    def seeker(self, key=None, retn=None):
        #search through database or/and return database
        if retn:
            return self.database
    
    def saveDB(self):
        #overwrites the old database
        with open(self.db_path, "w") as db:
            db = csv.writer(db)
            for key, val in self.database.items():
                db.writerow([key, val])



if "__main__"==__name__:
    userdata = "1", "2", "3", "4", "5", "7", "6", "8", "9", "10"
    db = Database()
    db.importDB("database.csv")
    db.appendUser(userdata)
    user = db.getUser("Customer_2")
    print user
    a = db.seeker(retn=True)
    print len(a.keys())
    db.saveDB()
"appendUser()" muss überarbeitet werden.

Hab bis jetzt noch nicht viel mit dicts und csv, datenbanken etc. gearbeitet, deswegen frag ich, ob der Aufbau im wesentlichen Stimmt?
BlackJack

@Dami123: Klassen sollten in der `__init__()` soweit initialisiert sein, dass sie einen konsistenzen Zustand haben und benutzbar sind. Das bedeutet unter anderen das alle Attribute dort auf einen sinvollen Wert gesetzt werden und im Gegenzug in keiner anderen Methode neue Attribute eingeführt werden.

Das `eval()` in `getUser()` ist zum schreiend weglaufen. Du führst damit Code aus CSV-Dateien aus, die sonstwas enthalten können.

In Python 2 sollte man von `object` erben wenn man sonst keine Basisklasse hat.

Die Schreibweise der Methodennamen entsprechen nicht den üblichen Konvention `kleinbuchstaben_mit_unterstrichen()`.

CSV-Dateien sollte man in Python 2 im Binärmodus öffnen.

Bei einer `import*()`-Methode, vor allem im zusammenhang mit Datenbanken, werden viele erwarten dass diese Daten zur Datenbank hinzufügt und nicht bereits vorhandene überschreibt.

`appendUser()` ist sehr spezifisch, währen die Klasse sehr allgemein benannt ist. Warum die Schlüssel alle den Präfix 'Customer_' tragen erschliesst sich mir nicht. Man hätte da auch einfach die Zahlen nehmen können. Und *dann* könnte man das vielleicht auch einfach ganz weg lassen können und die Daten in einer Liste speichern können, denn dort sind die Indizes ja implizit. Deine Schlüssel würden so sowieso nicht funktionieren sobald man Anfäng Datensätze zu löschen und dann neue hinzufügt. Dann werden Schlüssel potentiell doppelt vergeben und ein hinzugefügter Datensatz kann einen Vorhandenen einfach überschreiben. Bei der Ermittlung der nächsten Nummer wird auch unnötigerweise eine Liste der Schlüssel erstellt. Das Wörterbuch selber kennt doch schon seine eigene Länge ohne dass man da noch eine Liste erstellen müsste. An der Stelle würde man auch erwarten dass das Datenbank-Objekt eine Länge hat und man einfach ``len(self)`` hätte schreiben können.

Das mit `userdata` und den einbuchstabigen Namen ist äusserst unschön. Die könnte man sich sparen wenn man die Schlüssel und die Werte mit `zip()` oder `itertools.izip()` zusammenführt:

Code: Alles auswählen

        column_names = [
            'Bezeichnung', 'Strasse', 'Postleitzahl', 'Ort', 'Land', 'Tuer',
            'Treppe', 'Telefon', 'Fax', 'Postfach'
        ]
        self.rows.append(dict(izip(column_names, userdata)))
Wobei die `column_names` vielleicht nicht dort sondern als Attribut des Objekts definiert werden sollten. Dann ist man einem flexiblen Datenbank-Objekt das nicht nur Adressen speichern kann, näher.

Abkürzungen die nicht allgemein bekannt sind bei Namen sollte man vermeiden. Also `delete` statt `del`, `user` statt `usr`.

Die von `saveDB()` erstellte CSV-Datei ist nur formal eine. Das ist nicht das was man erwartet wenn jemand sagt er speichert eine Datenbanktabelle als CSV. Die kann man doch in der Form nicht in anderen Programmen, ausser selbst geschriebenen Python-Programmen verwenden. Normalerweise möchte man eine Tabellendatei mit den Werten in einzelnen Spalten und die mit einer Zeile mit den Spaltennamen beginnt. Damit man die Datei einfach in einer Tabellenkalkulation, eine andere Datenbanksoftware, oder zig andere Programme die dieses Format erwarten, einlesen kann. Beziehungsweise auch der umgekehrte Weg: Selbst so eine Datei lesen die von einem anderen Programm exportiert wurde.
Sirius3
User
Beiträge: 17755
Registriert: Sonntag 21. Oktober 2012, 17:20

@Dami123: in importDB schreibst Du Strings an Dein database-Objekt, bei appendUser dagegen Dictionaries. Warum übergibst Du appendUser überhaupt eine Liste mit festgelegten Einträgen. Einfacher verständlich waren 7 Parameter mit den passenden Namen, statt a,b,c,d...
Dami123
User
Beiträge: 225
Registriert: Samstag 23. Februar 2013, 13:01

@BlackJack Sehr gute Erklärungen der Mängel und Fehler 8)
Das "eval()" hab ich mir überlegt wegzulassen, müsste es aber als Empfänger wieder in eine dict umwandeln, sofern benötigt. Eine Kontrollfunktion wär auch ne Lösung.
"kleinbuchstaben_mit_unterstrichen" klingt gut.
Der DB sollten Daten hinzugefügt werden und die Zahlen Geschichte war wohl ein unvollständiger Denkansatz :?

Die Daten in einer Liste zu übergeben ist sogar sehr vorteilhaft, wie ich gerade sehe. Durch "column_names" als Ausrichtung, würde es ausreichen, lediglich "userdata" in die Datenbank zu schreiben und ggf. "column_names" einmalig. Das würde die Hälfte des benötigten Speichers sparen.

Die genauere Erstellung und Schreibweise und .csv Dateien schau ich mir an.

@Sirius3
Stimmt sind dict und String, sollte nicht vorkommen. Hab die Buchstaben gewählt, da ich keine Lust hatte alle auszuschreiben, ist ja nur nen Test gewesen. Werde aber die oben beschriebene list Variante verwenden.
Sirius3
User
Beiträge: 17755
Registriert: Sonntag 21. Oktober 2012, 17:20

Zur Inspiration:

Code: Alles auswählen

import csv
 
class Database(object):
    FIELDS = ()
    
    def __init__(self):
        self.database = []
 
    def importDB(self, db_path):
        with open(db_path, "r") as db:
            reader = csv.reader(db)
            header = next(reader)
            assert header, self.FIELDS
            self.database.extend(reader)
 
    def saveDB(self, db_path):
        with open(db_path, "w") as db:
            writer = csv.writer(db)
            writer.writerow(self.FIELDS)
            writer.writerows(self.database)

    def append(self, *data, **kw_data):
        data = list(data)
        print len(data),self.FIELDS[len(data):]
        for field in self.FIELDS[len(data):]:
            print field
            data.append(kw_data.pop(field))
        assert not kw_data, "Zu viele Felder angegeben: %s"%', '.join(kw_data)
        assert len(data)==len(self.FIELDS), "Zu wenige Felder angegeben"
        self.database.append(data)
 
    def get(self, index):
        return self.database[index]
    
    def query(self, **query):
        query = [(self.FIELDS.index(key),value) for key,value in query.iteritems()]
        return (entry for entry in self.database
                if all(entry[index]==value for index,value in query))
    
class UserDatabase(Database):
    FIELDS = (
        'Bezeichnung', 'Strasse', 'Postleitzahl', 'Ort', 'Land', 'Tuer',
        'Treppe', 'Telefon', 'Fax', 'Postfach'
    )
 
if "__main__"==__name__:
    userdata = "1", "2", "3", "4", "5", "7", "6", "8", "9", "10"
    db = UserDatabase()
    db.importDB('database.csv')
    db.append(*userdata)
    db.append('bla','fsd','sdfs',Ort='fds',Land='fdsf',Tuer='ofs',Treppe='',
              Telefon='06543',Fax='324',Postfach='343')
    print db.database
    print list(db.query(Ort='fds', Tuer='ofs'))
    db.saveDB('database.csv')
Antworten