Dies ist die Support Website des Buches:: Das Python Praxisbuch Der große Profi-Leitfaden für Programmierer Farid Hajji Addison Wesley / Pearson Education ISBN 978-3-8273-2543-3 (Sep 2008), 1298 Seiten. ******************************** 13. Persistenz und Datenbanken ******************************** Serialisieren und Deserialisieren ================================= Ein naiver Versuch mit str und eval ----------------------------------- Die richtige Lösung mit pickle ------------------------------ Screenshots: * `Dokumentation zum cPickle Modul `_ .. literalinclude:: ../att/persistence/mytype.py `mytype.py `_ Picklen mit ``dumps`` und ``loads``:: from cPickle import dumps, loads obj = MyType() obj_as_str = dumps(obj) obj2 = loads(obj_as_str) Picklen mit ``dump`` und ``load``:: from cPickle import dump, load out = open('/tmp/myobj.pickle', 'wb') dump(obj, out) out.close() inp = open('/tmp/myobj.pickle', 'rb') obj3 = load(inp) inp.close() Das funktioniert nur auf den ersten Blick scheinbar reibungslos:: from cPickle import dump, load class MyType(object): def hello(self): return "hello!" obj = MyType() dump(obj, open('/tmp/myobj.pickle', 'wb')) obj2 = load(open('/tmp/myobj.pickle', 'rb')) Aber wenn der Typ ``MyType`` aus der Datei :file:`mytype.p` kommt:: from mytype import MyType from cPickle import dump obj = MyType() dump(obj, open('/tmp/myobj.pickle', 'wb')) dann geht es:: >>> from cPickle import load >>> obj2 = load(open('/tmp/myobj.pickle', 'rb')) >>> obj2.hello() 'hello!' URLs: * `Informationen zum Modul pickle `_ Persistente Dictionarys mit anydbm ================================== Screenshots: * `Dokumentation zum anydbm Modul `_ Eine naive suboptimale Lösung ----------------------------- Die richtige Lösung mit anydbm ------------------------------ Ein persistentes Dictionary mit ``anydbm``:: import anydbm d = anydbm.open('/tmp/dictstore.db', 'c', 0600) d['one'] = 'eins' d['two'] = 'zwei' d['three'] = 'drei' d.close() Besonderheiten von anydbm Dictionarys ------------------------------------- Die anydbm-Architektur ---------------------- Mehr Flexibilität mit bsddb =========================== Ein sortiertes persistendes Dictionary mit ``bsddb``:: import bsddb d = bsddb.btopen('/tmp/dictstore2.db', 'c', 0600) d['one'] = 'eins' d['two'] = 'zwei' d['three'] = 'drei' d['four'] = 'vier' d['five'] = 'fuenf' d.sync() d.close() Screenshots: * `Dokumentation zum bsddb Modul `_ * `Dokumentation zu den Funktionen hashopen, btopen und rnopen `_ Persistente Datenstrukturen mit shelve ====================================== .. literalinclude:: ../att/persistence/personal.py `personal.py `_ Eine umständliche Lösung ------------------------ Man könnte ``shelve`` manuell mit ``anydbm`` und ``cPickle`` nachbilden:: from personal import Personal from cPickle import dumps import anydbm d = anydbm.open('/tmp/personal.store', 'c', 0600) p1 = Personal('0001', 'John', 'R', 'Doe') d[p1.pid] = dumps(p1) d.close() und wieder auslesen:: >>> from cPickle import loads >>> import anydbm >>> d = anydbm.open('/tmp/personal.store', 'r') >>> p1 = loads(d['0001']) >>> p1 >>> str(p1) 'Personal(0001, John R. Doe)' >>> p1.surname 'Doe' Beim Verändern von Einträgen muss man aufpassen:: from cPickle import dumps, loads import anydbm d = anydbm.open('/tmp/personal.store', 'w') p1 = loads(d['0001']) p1.middlename = 'S' d[p1.pid] = dumps(p1) d.close() Die shelve-Lösung ----------------- ``shelve`` benutzen:: from personal import Personal import shelve p1 = Personal('0001', 'John', 'R', 'Doe') p2 = Personal('0002', 'Martin', 'S', 'Bishop') p3 = Personal('U100', 'John', 'P', 'McKittrick') s = shelve.open('/tmp/personal.shelve') s[p1.pid] = p1 s[p2.pid] = p2 s[p3.pid] = p3 s.close() Screenshots: * `Dokumentation zum shelve Modul `_ shelve-Gotchas ^^^^^^^^^^^^^^ shelve mit Gedächtnis ^^^^^^^^^^^^^^^^^^^^^ Die ZODB-objektorientierte Datenbank ==================================== ZODB installieren ----------------- Die ZODB benutzen ----------------- .. literalinclude:: ../att/persistence/personal.py `personal.py `_ .. literalinclude:: ../att/persistence/ppersonal.py `ppersonal.py `_ Persistenz durch Erreichbarkeit ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Worauf man bei ZODB achten muss ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ein Performance-Tipp ^^^^^^^^^^^^^^^^^^^^ Screenshots: * `Dokumentation zu den ZODB BTrees `_ Weiterführende Informationen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ URLs: * `Die ZODB-Dokumentation `_ * `ZODB/ZEO Programming Guide `_ von A. M. Kuchling * `Introduction to the Zope Object Database `_ von Jim Fulton Ein Blogs-Backend mit ZODB ========================== Comment, Article und Blog ------------------------- .. literalinclude:: ../att/persistence/zcomment.py `zcomment.py `_ .. literalinclude:: ../att/persistence/zarticle.py `zarticle.py `_ .. literalinclude:: ../att/persistence/zblog.py `zblog.py `_ Das Blog-Backend BlogDB ----------------------- .. literalinclude:: ../att/persistence/zblogdb.py `zblogdb.py `_ DB-API 2.0 SQL-Anbindungen ========================== Eine kurze DB-API 2.0 Einführung -------------------------------- URLs: * `PEP 249 - Python Database API Specification v2.0 `_ SQLite-Anbindung mit sqlite3 ============================ Screenshots: * `Die SQLite3 Website `_ * `Das sqlite3 Python Modul `_ URLs: * `Homepage der SQLite3 C-Library `_ * `Homepage des sqlite3 Python Moduls `_ (ist aber in Python 2.5 und später integriert) sqlite3 benutzen ---------------- Das sqlite3-Tool ---------------- URLs: * `Einführung in das sqlite Tool `_ Manuell eine Tabelle anlegen:: $ sqlite3 /tmp/blogdb.sqlite3 SQLite version 3.4.1 Enter ".help" for instructions sqlite> CREATE TABLE comments ( ...> id INTEGER PRIMARY KEY AUTOINCREMENT, ...> subject TEXT, ...> author TEXT, ...> text TEXT ...> ); sqlite> .quit Die Datei ``blogdb.schema`` sieht so aus: .. literalinclude:: ../att/persistence/blogdb.schema :language: sql `blogdb.schema `_ Tragen wir testweise was ein:: $ sqlite3 /tmp/blogdb.sqlite3 SQLite version 3.4.1 Enter ".help" for instructions sqlite> INSERT INTO blogs VALUES ( ...> 'The Python Blog', ...> 'Farid Hajji', ...> 'A blog about Python, what else?' ...> ); sqlite> INSERT INTO blogs VALUES ( ...> 'The Perl Blog', ...> 'Farid Hajji', ...> 'There is more than one way to do it!' ...> ); sqlite> .quit Das sqlite3-Modul ----------------- Anwendung: Verwaltung von MP3-Metadaten --------------------------------------- .. literalinclude:: ../att/persistence/mp3scan.py `mp3scan.py `_ .. literalinclude:: ../att/persistence/mp3tree.py `mp3tree.py `_ Benötigt werden auch folgende Module: * `parseid3.py `_ aus `Anwendung: Auslesen von mp3 ID3v1-Tags `_ * `fingerprint.py `_ aus `Anwendung: Prüfsummen `_ .. literalinclude:: ../att/persistence/mp3initdb_sqlite3.py `mp3initdb_sqlite3.py `_ .. literalinclude:: ../att/persistence/mp3db_sqlite3.py `mp3db_sqlite3.py `_ PostgreSQL-Anbindung mit psycopg2 ================================= Was ist PostgreSQL? ------------------- URLs: * `PostgreSQL Homepage `_ Screenshots: * `PostgreSQL About Seite `_ PostgreSQL installieren ----------------------- Unix ^^^^ FreeBSD-spezifisches Startup Script: * `/usr/local/etc/rc.d/postgresql `_ Windows ^^^^^^^ Screenshots: * `Auswahl der PostgreSQL Komponenten `_ * `Die Datenbank-Instanz initialisieren `_ * `Das PostgreSQL Edit pg_hba.conf Menü `_ * `Eigenes Subnetz in die pg_hba.conf eintragen `_ * `listen_addresses in postgresql.conf kontrollieren `_ * `Mit psql an den FreeBSD DB-Server connecten `_ * `Mit psql eine Abfrage dorthin senden `_ * `Den PostgreSQL Serverport 5432 in der Windows Firewall zulassen `_ * `In pgAdmin III den FreeBSD DB-Server anmelden `_ * `pgAdmin III's Sicht auf die emails Tabelle `_ * `Editierbare Tabelle mit pgAdmin III `_ * `Mit createuser und createdb Benutzer und DB auf dem Windows-DBServer erzeugen `_ * `Auf dem Windows-DBServer die Tabelle emails erzeugen `_ * `Auf dem Windows-DBServer die Tabelle emails abfragen und löschen `_ psycopg2 installieren --------------------- psycopg2 unter Unix installieren ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ URLs: * `Die im Buch verwendete Version von psycopg2 `_ (mit ``easy_install psycopg2`` wird aber die neueste Version installiert) Der Patch für FreeBSD: .. code-block:: diff --- psycopg/config.h.orig 2007-04-11 12:12:37.000000000 +0000 +++ psycopg/config.h 2007-07-02 14:41:35.000000000 +0000 @@ -113,7 +113,7 @@ #define inline #endif -#if defined(__FreeBSD__) || (defined(_WIN32) && !defined(__GNUC__)) \ || defined(__sun__) +#if (defined(_WIN32) && !defined(__GNUC__)) || defined(__sun__) /* what's this, we have no round function either? */ static double round(double num) { psycopg2 unter Windows installieren ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ URLs: * `Ein vorkompiliertes Modul für Windows `_ (``win-psycopg`` Projekt) Screenshots: * `Der Aufruf easy_install --editable psycopg2 unter Windows `_ * `setup.cfg anpassen `_ psycopg2 benutzen ----------------- URLs: * `Das PostgreSQL Manual `_ Screenshots: * `Die verschiedenen Transaction-Levels von PostgreSQL `_ * `Das PostgreSQL Manual Screenshot `_ Anwendung: MP3-Metadaten unter PostgreSQL ----------------------------------------- .. literalinclude:: ../att/persistence/mp3initdb_pgsql.py `mp3initdb_pgsql.py `_ .. literalinclude:: ../att/persistence/mp3db_pgsql.py `mp3db_pgsql.py `_ MySQL-Anbindung mit MySQLdb =========================== URLs: * `MySQL Homepage `_ MySQL-Datenbank vorbereiten --------------------------- Die pybookdb-Datenbank anlegen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Die pybookdb-Datenbank testen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ MySQL-python installieren ------------------------- URLs: * `MySQL-python Homepage `_ (aber besser mit ``easy_install MySQL-python`` installieren) Unix ^^^^ Windows ^^^^^^^ Screenshots: * `Der Aufruf easy_install MySQL-python `_ MySQL-python benutzen --------------------- Anwendung: MP3-Metadaten unter MySQL ------------------------------------ .. literalinclude:: ../att/persistence/mp3initdb_mysql.py `mp3initdb_mysql.py `_ .. literalinclude:: ../att/persistence/mp3db_mysql.py `mp3db_mysql.py `_ Der objektrelationale Mapper SQLObject ====================================== Was sind objektrelationale Mapper? ---------------------------------- URLs: * `Website von SQLObject `_ * `Dokumentation von SQLObject `_ Screenshots: * `Website von SQLObject Screenshot `_ SQLObject installieren ---------------------- URLs: * `Die im Buch benutze Version von SQLObject `_ (aber besser ``easy_install SQLObject`` aufrufen) * `Als Abhängigkeit wurde FormEncode installiert `_ (aber s. oben) Screenshots: * `Der Aufruf von easy_install SQLObject unter Windows `_ SQLObject benutzen ------------------ Eine Verbindung zur Datenbank herstellen ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Screenshots: * `Diverse DSN-Schemata für SQLObject `_ Eine persistente Klasse definieren ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Definieren wir als Beispiel die Klasse ``Comment``:: class Comment(SQLObject): subject = StringCol(length=50) body = StringCol() author = StringCol(default='Anonymous') added = DateTimeCol(default=DateTimeCol.now) Screenshots: * `Verschiedene SQLObject Typen für Spalten `_ Die Datenbank abfragen ^^^^^^^^^^^^^^^^^^^^^^ 1:N- und N:M-Beziehungen ^^^^^^^^^^^^^^^^^^^^^^^^ Eine 1:N-Beziehung:: class Person(SQLObject): name = StringCol() contacts = MultipleJoin('Contact') class Contact(SQLObject): email = StringCol() phone = StringCol() person = ForeignKey('Person') Person.createTable() Contact.createTable() Eine N:M-Beziehung:: class Employee(SQLObject): name = StringCol() roles = RelatedJoin('Role') class Role(SQLObject): descr = StringCol() employees = RelatedJoin('Employee') Das Blog-System mit SQLObject ----------------------------- .. literalinclude:: ../att/persistence/soblogs.py `soblogs.py `_ Eine typische Sitzung:: from sqlobject import * from soblogs import * SoBlogs(createTables=True, debug=False) b = Blog(name='SQLObject Blog', author='Farid Hajji', descr='A blog to discuss SQLObject issues') a1 = Article(title='Installing SQLObject is easy', author='Farid', text='Just run "easy_install SQLObject" to install', blog=b) a2 = Article(title='Joins in SQLObject', author='A Blogger', text='Use ForeignKey and MultipleJoin for 1:N', blog=b) a3 = Article(title='Joins in SQLObject (II)', author='A Blogger', text='Use RelatedJoin on both sides of a N:M relationship', blog=b) c11 = Comment(subject='URL needed', author='Anonymous', text='Need to add an -f URL to easy_install', article=a1) Screenshots: * `Die Tabelle article in pgAdmin III `_ django.db, ein anderer ORM -------------------------- .. NYI Wird in ` <>`_ behandelt. URLs: * `Die Dokumetation von models.Model `_ Screenshots: * `Die django.db Dokumentation `_ Zusammenfassung ===============