Mit SQlite Objekte speichern, was bringt das eigentlich ?

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

Hallo mal wieder,

bezüglich meiner Miethausverwaltung (aktuelle Version (auch noch ziemlich unterentwickelt) liegt hier) suche ich nach einer Möglichkeit, vom Nutzer angelegte Daten auch dauerhaft und sicher speichern zu können. Nach einer etwas krampfigen Einarbeit in sqlite funktioniert mein Testskript (hier) auch endlich ungefähr so, wie ich mir das vorstelle.

Nur, später gibts ja ungefähr zigmillionen Objekte, Blumen oder Mieter, was auch immer. Wenn ich dann aber sowas anfragen will, wie "alle Mieter anzeigen, die zu spät Miete gezahlt haben" muss ich ja, um auf die entsprechenden Eigenschaften der gespeicherten Objekte zugreifen zu können, sämtliche Datenbankeinträge erst mal in Objekte umwandeln, um dann in denen wiederum nach den gefragten Eigenschaften zu suchen.

Das würde doch aber für eine relativ hohe Speicherbelastung sorgen und kommt mir auch irgendwie unsinnig vor.

Dazu kommt auch noch, daß z.B. mein "Wohnung"-Objekt eine Liste aller jemals eingezogenen Mieter enthält, welche man ja wieder nur über Umwege in der DB abspeichern könnte.

Jetzt aber nur direkt mit Datenbankeintragungen zu arbeiten, finde ich dann auch wieder inkonsequent, ich will doch meine tollen Methoden benutzen (siehe Miethauscode), wie z.B. "Mieter in Wohnung einziehen lassen".

Ich weiß grad irgendwie nicht, in welche Richtung ich jetzt weitergehen soll. Mein Datenbankansatz kommt mir nicht schlüssig vor. Meine Miethausverwaltung aber wenigstens son bißchen. Oder sollte ich letztere unter dem Aspekt der Datenspeicherung besser völlig anders aufbauen ? Wie macht man sowas ?
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

Was du suchst ist ein ORM (Object Relational Mapper) also den Kleber zwischen Objekten und Tabellarischen (rationalen) Datenbanken. Google mal nach SQLAlchemy.
Bottle: Micro Web Framework + Development Blog
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

mhm, hat mir cofi auch schon vorgeschlagen, bleibt das Problem des SQL-Servers. Kann ich den prinzipiell so in eine Installationsroutine verpacken, daß der Endnutzer, wenn er denn dann mein tolles Programm installiert, damit nix zu tun hat ?
BlackJack

Die `sqlite3`-Bibliothek sollte bei Windows zum Lieferumfang von Python gehören und bei Linux ist's halt eine Abhängigkeit, die über die Paketverwaltung automatisch nachgezogen wird.
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

heißt das, ich kann mit sqlite auf SQLalchemy zugreifen oder wie ?
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Nein, andersrum. SQLAlchemy ist eine Abstraktionsschicht ueber der Datenbank, damit du dich nicht damit rumschlagen musst.
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

heißt, ich müsste mir nur die SQLalchemy "Abstraktionsschicht" installieren und kann dann damit eine sqlite3 Datenbank bedienen ??
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

SQLAlchemy ist pure Python, d.h. du musst das sogar nur in den Ordner deines Programms legen. Die Datenbank kannst du auch so bedienen, allerdings nicht um damit ganze Objekte zu speichern, du muesstest die vorher serialisieren.
Den ganzen Kram erledigt SQLAlchemy.
Bevor du aber eine Datenbank damit fuettern kannst, solltest du dich erstmal in SQLAlchemy einlesen ;)
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

werd ich gerne, brauchte nur mal so eine Aussage zum grundlegenden Verständnis, aber das scheint ja schon genau das zu sein, was ich gesucht habe. Dann werd ich mal lesen, danke und bis später,
Benutzeravatar
Defnull
User
Beiträge: 778
Registriert: Donnerstag 18. Juni 2009, 22:09
Wohnort: Göttingen
Kontaktdaten:

cofi hat geschrieben:... du muesstest die vorher serialisieren. Den ganzen Kram erledigt SQLAlchemy.
Mit dem Unterschied, das SQLAlchemy nicht einfach alles durch pickle jagt, sondern Datenbanken so verwendet, wie sie gedacht sind.

Grob zusammengefasst funktioniert das so:

Jedes von SQLAlchemy gemappte Objekt ist einer Tabelle in der Datenbank zugeordnet. Jedes Attribut des Objektes ist eine Spalte in der passenden Tabelle. Wenn du ein Objekt lädst, baut es SA aus den Daten in der Datenbank für dich zusammen. Wenn du es veränderst und dann speicherst, werden die Daten wieder in die Datenbank geschrieben. Da jedes Attribut der Objekte in einer eigenen Spalte steht, kann man darin suchen. Du kannst dir von SA also z.B. alle Blumen geben lassen, die rot sind, ohne jede einzelne Blume laden zu müssen.

Wenn du Assoziationen richtig definierst, kannst du auch z.B. eine Wohnung laden und von da aus direkt auf die Mieter der Wohnung zu greifen. SA weist dann nämlich, welche Mieter zu welcher Wohnung gehören.

Allerdings sollte man SQL oder wenigstens das Prinzip von relationalen Datenbanken verstanden und verinnerlicht haben, bevor man sich an SQLAlchemy wagt. Einfach ist dieses ORM System nämlich nicht. Dafür ist es allerdings mächtig
Bottle: Micro Web Framework + Development Blog
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Ich würde so weit gehen und sagen, SQLalchemy ist viel zu kompliziert. Einfacher ist da z.B. http://www.sqlobject.org/ oder http://autumn-orm.org/.

Komplett von einer DB zu abstrahieren ist IMHO auch nicht der richtige Weg. Eigentlich ist Microsoft LINQ-Ansatz richtig. Von Nathan Sobo habe ich neulich eine Talk über eine JavaScript-Bibliothek gesehen, die einem Joins und Projections auf JavaScript-Objekten erlaubte, also den Kern einer RDB nicht versucht hat zu verstecken sondern im Gegenteil anzubieten. So etwas könnte man natürlich genauso gut auch in Python benutzen.

Stefan
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wieso eigentlich wird Elixir so selten empfohlen? Imho für den Einstieg ideal.
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

jut, dann hab ich mich also zumindest schon mal bruchstückhaft in diesen Chemiebaukasten eingelesen. Das Tutorial entspricht gott sei Dank auch zeimlich genau meinem ersten Konstrukt, nämlich Haus und seine Wohnungen. Funktioniert auch so, wie es soll. Die Herangehensweise gefällt mir so eigentlich ganz gut. (hier mal schaun, da ist er, der Code)

Soweit hab ich die Arbeitsweise auch grob verstanden.

Erstes Problem: Laut Tutorial kann man ja die deklarative Methode benutzen, um die entsprechende Tabelle für das jeweilige Objekt anzulegen. Das versteh ich da so, daß ich mir diese anfängliche Schreiberei von Zeile 10 bis 24 eigentlich sparen kann, kommt ja alles nochmal in der Klasse. Geht bei mir nur irgendwie nicht, wenn das da nicht steht, legt der Kollege keine Tabellen an.

Zweite und wichtigere Frage: hat sich grad erst mal zurückgestellt.

und @Hyperion: Elixir ist also eine Abstraktionsschicht, die SQLAlchemy abstrahiert, also doppelt abstrakt oder wie ?

edit: Ja, genau, da materialisierte sich die zweite Frage auch schon wieder:

Die Wohnungen sollen eigentlich als Attribut eine Liste aller Mieter (oder deren id, wäre egal), die dort jemals gewohnt haben, haben, kombiniert mit Einzugs- und Auszugsdatum. Jetzt kann ich aber keine Liste mehr als Attirbut benutzen, oder ?
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Elixir sollte sich eigentlich mit <http://www.sqlalchemy.org/docs/05/refer ... ative.html> erledigt haben. Da ich aber Djangos ORM einfacher finde, hier mal das Beispiel:

Code: Alles auswählen

class Home(models.Model):
    street = models.CharField()
    city = models.CharField()
    
class Flat(models.Model):
    square_meters = models.IntegerField()
    home = models.ForeignKey(Home, related_name="flats")

class Tenant(models.Model):
    name = models.CharField()
    current_flat = models.ForeignKey(Flat, related_name="tenants")
Stefan
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

das liest sich schon ein wenig einfacher, als das, was ich hier grad am produzieren bin. Jetzt bringt mich doch nicht völlig durcheinander.

Kann ich denn mit diesem Django ORM auch das realisieren:

Eine Liste mit Listen aller Mieter, die schonmal in der Wohnung gewohnt haben in der Form (Mieterobjekt, Einzugsdatum, Auszugsdatum), die dann als Attribut der Wohnung geführt wird ?
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Würde ich mit einem "Mietverhältnis" modellieren:

Code: Alles auswählen

class Tenancy(models.Model):
    moved_in = models.DateField()
    moved_out = models.DateField()
    tenant = models.ForeignKey(Tenant, related_name="tenancies")
    flat = models.ForeignKey(Flat, related_name="tenancies")
Liste aller Mieter einer Wohnung:

Code: Alles auswählen

class Flat...
    def all_tenants(self):
        return [(t.tenant.name, t.moved_in, t.moved_out) 
            for t in self.tenancies.order_by('moved_in')]
Es müsste noch einen effizienteren Weg geben, an den Namen des Mieters zu kommen, irgendwas mit `select_related`, doch ich bin zu faul zum Nachgucken.

Stefan
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

ah ok, ich war da so in ähnlicher Richtung unterwegs:

Code: Alles auswählen

class FlatsTenantHistory(Base):
    
    __tablename__ = 'flats_tenant_history'
    id = Column(Integer, primary_key=True)
    tenant_id = Column(Integer, nullable=False)
    date_of_move_in = Column(String)
    flat_id = Column(Integer, ForeignKey('flats.id'))

    tenant = relation(Flat, backref=backref('flats_tenant_history',
                                            order_by=id))

    def __init__(self, tenant_id, date_of_move_in):
        self.tenant_id = tenant_id
        self.date_of_move_in = date_of_move_in
, wobei deine Bezeichnung "Mietverhältnis" mir grad mal klargemacht hat, was ich da eigentlich selber mit meine. Nur bei mir wird nur die MieterID gespeichert. Versteh ich das richtig, daß

Code: Alles auswählen

tenant = models.ForeignKey(Tenant, related_name="tenancies")
also so eine Art Zeiger auf diesen speziellen Mieter ist ? Wär ja eigentlich dann so, wie es meinem Verständnis nach sein sollte.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

tenant referenziert für ein spezielles Exemplar dieser Klasse zu einem anderen Objekt derjenigen Klasse, die du im ForeignKey angibst, hier als Tenant. tenancies ist dann der Name einer Art Menge, die alle FlatsTenantHistory Objekte welche wie grade beschrieben in Beziehung zu Tenant stehen beinhaltet.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Der "related_name" bei Django ist die Rückrichtung der 1:N Assoziation, d.h. zu einem Mietverhältnis gehört eine Wohnung, wie man über "flat" erreicht und von der Wohnung aus kommt man mit "tenancies" zu alle Mietverhältnissen für diese Wohnung.

Stefan
ippurk
User
Beiträge: 61
Registriert: Mittwoch 8. Juli 2009, 20:40

So, da hab ich jetzt zumindest grundlegend dieses SA verstanden und wollte hier mal fragen, ob mein Code denn in der Form ausbaufähig ist, oder eher einer Komplettüberarbeitung bedarf: http://paste.pocoo.org/show/134848/

(es geht immer noch um die Miethausverwaltung)

Schönen Gruß, Stephan
Antworten