Archiv 16.7.2005 - 31.7.2005

Einfacher Dateisystem-Browser mit Django schreiben

Dieser Artikel ist mal wieder in Englisch, da er auch für die Leute auf #django interessant sein könnte. Dieser Beitrag zeigt, wie man einen sehr einfachen Dateisystem-Browser mit Django erstellt. Dieser Dateisystem-Browser verhält sich größtenteils wie ein statischer Webserver, der die Verzeichnisnavigation ermöglicht. Die einzige Besonderheit ist, dass Sie das Django-Admin verwenden können, um Dateisysteme zu definieren, die in den Namensraum des Django-Servers eingebunden werden. Dies dient nur zur Demonstration, wie eine Django-Anwendung verschiedene Datenquellen neben der Datenbank nutzen kann. Es ist nicht wirklich dazu gedacht, statischen Inhalt zu servieren (obwohl es mit hinzugefügter Authentifizierung quite nützlich für eingeschränkten statischen Inhalt sein könnte!).

Auch wenn die Anwendung sehr einfache Sicherheitsprüfungen an den übergebenen Dateinamen durchführt, sollten Sie dies nicht auf einem öffentlichen Server ausführen - ich habe keine Sicherheitstests durchgeführt und es könnte buttloads von schlechten Dingen geben, die Ihre privaten Daten der Welt preisgeben könnten. Sie wurden gewarnt. Wir beginnen wie üblich mit der Erstellung der Dateisystem-Anwendung mit dem Befehl django-admin.py startapp filesystems. Machen Sie es einfach so, wie Sie es mit Ihrer Umfrageanwendung im ersten Tutorial gemacht haben. Nur zur Orientierung, so sieht die myproject-Verzeichnis auf meiner Entwicklungsmaschine aus:


.
|-- apps
| |-- filesystems
| | |-- models
| | |-- urls
| | `-- views
| `-- polls
| |-- models
| |-- urls
| `-- views
|-- public_html
| `-- admin_media
| |-- css
| |-- img
| | `-- admin
| `-- js
| `-- admin
|-- settings
| `-- urls
`-- templates
 `-- filesystems

Nach der Erstellung der Infrastruktur beginnen wir mit dem Aufbau des Modells. Das Modell für die Dateisysteme ist sehr einfach - nur ein Name für das Dateisystem und ein Pfad, an dem die Dateien tatsächlich gespeichert sind. Hier ist es also, das Modell:


 from django.core import meta

class Filesystem(meta.Model):

fields = ( meta.CharField('name', 'Name', maxlength=64), meta.CharField('path', 'Path', maxlength=200), )

def repr(self): return self.name

def get_absolute_url(self): return '/files/%s/' % self.name

def isdir(self, path): import os p = os.path.realpath(os.path.join(self.path, path)) if not p.startswith(self.path): raise ValueError(path) return os.path.isdir(p)

def files(self, path=''): import os import mimetypes p = os.path.realpath(os.path.join(self.path, path)) if not p.startswith(self.path): raise ValueError(path) l = os.listdir(p) if path: l.insert(0, '..') return [(f, os.path.isdir(os.path.join(p, f)), mimetypes.guess_type(f)[0] or 'application/octetstream') for f in l]

def file(self, path): import os import mimetypes p = os.path.realpath(os.path.join(self.path, path)) if p.startswith(self.path): (t, e) = mimetypes.guess_type(p) return (p, t or 'application/octetstream') else: raise ValueError(path)

admin = meta.Admin( fields = ( (None, {'fields': ('name', 'path')}), ), list_display = ('name', 'path'), search_fields = ('name', 'path'), ordering = ['name'], )


Wie Sie sehen können, ist das Modell und das Admin eher langweilig. Was interessant ist, sind jedoch die zusätzlichen Methoden `isdir`, `files` und `file`. `isdir` überprüft, ob ein gegebener Pfad unter dem Dateisystem ein Verzeichnis ist oder nicht. `files` gibt die Dateien des angegebenen Pfades unter dem Basispfad des Dateisystems zurück und `file` gibt den echten Dateipfad und den MIME-Typ einer gegebenen Datei unter dem Basispfad des Dateisystems zurück. Alle drei Methoden überprüfen die Gültigkeit des übergebenen Pfades - wenn der resultierende Pfad nicht unter dem Basispfad des Dateisystems liegt, wird eine ValueError ausgelöst. Dies soll sicherstellen, dass niemand `..` im Pfadnamen verwendet, um aus dem definierten Dateisystem-Bereich auszubrechen. Das Modell enthält also spezielle Methoden, die Sie verwenden können, um auf den Inhalt des Dateisystems selbst zuzugreifen, ohne sich Gedanken darüber zu machen, wie dies in Ihren Ansichten zu tun ist. Es ist die Aufgabe des Modells, solche Dinge zu kennen.

Der nächste Teil Ihres kleinen Dateisystem-Browsers wird die URL-Konfiguration sein. Sie ist eher einfach, sie besteht aus der Zeile in `settings/urls/main.py` und dem Modul `myproject.apps.filesystems.urls.filesystems`. Zuerst die Zeile im Haupt-URLs-Modul:

from django.conf.urls.defaults import *

urlpatterns = patterns('', (r'^files/', include('myproject.apps.filesystems.urls.filesystems')), )


Als nächstes das eigene URLs-Modul der Dateisysteme:

from django.conf.urls.defaults import *

urlpatterns = patterns('myproject.apps.filesystems.views.filesystems', (r'^$', 'index'), (r'^(?P.?)/(?P.)$', 'directory'), )


Sie können die Anwendung nun der Haupt-Einstellungsdatei hinzufügen, damit Sie es später nicht vergessen. Suchen Sie einfach nach der Einstellung INSTALLED_APPS und fügen Sie den Dateibrowser hinzu:

INSTALLED_APPS = ( 'myproject.apps.polls', 'myproject.apps.filesystems' )


Ein Teil fehlt noch: die Ansichten. Dieses Modul definiert die extern erreichbaren Methoden, die wir im URL-Mapper definiert haben. Wir benötigen also zwei Methoden, `index` und `directory`. Die zweite funktioniert tatsächlich nicht nur mit Verzeichnissen - wenn sie eine Datei übergeben bekommt, präsentiert sie einfach den Inhalt dieser Datei mit dem richtigen MIME-Typ. Die Ansicht macht Gebrauch von den in dem Modell definierten Methoden, um auf den tatsächlichen Dateisysteminhalt zuzugreifen. Hier ist der Quellcode für das Ansichtsmodul:

from django.core import template_loader from django.core.extensions import DjangoContext as Context from django.core.exceptions import Http404 from django.models.filesystems import filesystems from django.utils.httpwrappers import HttpResponse

def index(request): fslist = filesystems.getlist(orderby=['name']) t = templateloader.gettemplate('filesystems/index') c = Context(request, { 'fslist': fslist, }) return HttpResponse(t.render(c))

def directory(request, filesystem_name, path): import os try: fs = filesystems.getobject(name exact=filesystemname) if fs.isdir(path): files = fs.files(path) tpl = templateloader.gettemplate('filesystems/directory') c = Context(request, { 'dlist': [f for (f, d, t) in files if d], 'flist': [{'name':f, 'type':t} for (f, d, t) in files if not d], 'path': path, 'fs': fs, }) return HttpResponse(tpl.render(c)) else: (f, mimetype) = fs.file(path) return HttpResponse(open(f).read(), mimetype=mimetype) except ValueError: raise Http404 except filesystems.FilesystemDoesNotExist: raise Http404 except IOError: raise Http404


Sehen Sie, wie die Elemente des Verzeichnismusters als Parameter an die Directory-Methode übergeben werden - der Dateisystemname wird verwendet, um das richtige Dateisystem zu finden, und der Pfad wird verwendet, um den Inhalt unter dem Basispfad dieses Dateisystems zuzugreifen. MIME-Typen werden mit dem mimetypes-Modul aus der Python-Distribution ermittelt, übrigens.

Der letzte Teil unseres kleinen Tutorials sind die Vorlagen. Wir benötigen zwei Vorlagen - eine für den Index der definierten Dateisysteme und eine für den Inhalt eines Pfades unter einem Dateisystem. Wir benötigen keine Vorlage für den Dateiinhalt - der Dateiinhalt wird roh geliefert. Zuerst also die Hauptindexvorlage:

{% if fslist %}

definierte Dateisysteme

{% else %}

Entschuldigung, es wurden keine Dateisysteme definiert.

{% endif %}

Die andere Vorlage ist die Verzeichnisvorlage, die den Inhalt eines Pfades unter dem Basispfad des Dateisystems anzeigt:

{% if dlist or flist %}

Dateien in //{{ fs.name }}/{{ path }}

    {% for d in dlist %}
  • {{ d }}
  • {% endfor %} {% for f in flist %}
  • {{ f.name }} ({{ f.type }})
  • {% endfor %}
{% endif %}


Beide Vorlagen müssen irgendwo in Ihrem TEMPLATE-PFAD gespeichert werden. Ich habe einen Pfad im TEMPLATE-PFAD mit dem Namen der Anwendung eingerichtet: `filesystems`. Dort habe ich die Dateien als `index.html` und `directory.html` gespeichert. Natürlich würden Sie normalerweise eine Basisvorlage für die Website erstellen und diese in Ihren normalen Vorlagen erweitern. Und Sie würden eine `404.html` hinzufügen, um 404-Fehler zu behandeln. Aber das bleibt als Übung für den Leser. Nachdem Sie Ihren Entwicklungsserver für Ihr Admin gestartet haben (vergessen Sie nicht, DJANGO SETTINGS MODULE entsprechend einzustellen!), können Sie ein Dateisystem zu Ihrer Datenbank hinzufügen (haben Sie irgendwann zwischenzeitlich `django-admin.py install filesystems` gemacht? Nein? Machen Sie es jetzt, bevor Sie Ihren Server starten). Jetzt stoppen Sie den Admin-Server, ändern Sie Ihr DJANGO SETTINGS MODULE und starten Sie den Haupt-Einstellungsserver. Jetzt können Sie zu [http://localhost:8000/files/](http://localhost:8000/files/) surfen (zumindest wenn Sie Ihre URLs und Ihren Server so eingerichtet haben wie ich) und die Dateien in Ihrem Dateisystem durchsuchen. Das ist alles. War nicht sehr kompliziert, oder? Django ist wirklich einfach zu verwenden.

Zerospan scheint eine P2P-Software mit Verschlüsselung und Integration von Bonjour (ex-Rendevouz, ex-Zeroconf) zu sein. So richtig schlau werd ich nicht draus, denn der Download enhält keine Doku und das Wiki mit der Doku ist zur Zeit kaputt, daher mal geblogmarked um es mir später mal anzugucken.

Ausbildung als Billiglohnschiene

Was hinter der Forderung des DIHK nach Halbierung des Lehrlingsgrundgehaltes und Flexibilisierung der Arbeitszeiten steckt, wird einem klar wenn man sich Zitate des DIHK-Vorsitzenden ansieht:

"Mein Vorschlag ist, eine bundesweite Basisvergütung von 270 Euro einzuführen", sagte er der Zeitung "Die Welt". Er rechtfertigte seinen Vorstoß damit, dass so mehr Lehrstellen finanziert werden könnten. "Eine Ausbildungsvergütung von bis zu 800 Euro ist für viele Betriebe einfach zu hoch."

"Die Arbeitszeiten müssen den Bedürfnissen der Branchen besser angepasst werden." Es ergebe keinen Sinn, dass eine 17-jährige Restaurantfachfrau um 22.00 Uhr gehen müsse, "wenn noch alle Tische besetzt sind"

Da gehts einfach nur darum billige Arbeitskräfte zu haben, aber nicht darum eine fachgerechte Ausbildung zu gewährleisten. Aber die Forderungen sind ja nicht neu.

Und was die deutsche Wirtschaft von Ausbildung hält, sieht man ja auch an der Tatsache das die Ausbildungsplätze im Vergleich zum Vorjahr wieder 10% runter sind - und damit wieder Jugendliche ohne Ausbildungsplätze geblieben sind, trotz aller Versprechungen der Wirtschaft. Ohne Nichtausbildungsabgabe für grössere Unternehmen wird sich das auch nicht ändern. Aber darüber jammern das es keine ausgebildeten Fachkräfte gibt, das kann die Wirtschaft ganz famos ...

Beckstein on the Roll

Keine Ahnung wie das Kraut heisst das er nimmt, aber es hinterlässt schwere Hirnschäden: Beckstein will deutsches Guantanamo. Abgesehen davon das er auch Verdächtigen in den Kopf schiessen will und Ausländer erstmal in Lager packen will, weil ja auf keinen Fall potentielle Terroristen frei rumlaufen dürfen (durchgeknallte Politiker wie er dürfen aber nicht nur frei rumlaufen sondern auch noch frei ihre Meinung äussern), er ist auch verfassungsfeindlich eingestellt:

Beckstein kritisierte auch das Urteil des Bundsverfassungsgericht, dass in einem Urteil zur niedersächsischen Gesetzgebung klare Eingrenzungen bei der vorbeugenden Telefonüberwachung verlangt hatte. Es müsse zwischen Sicherheits- und Freiheitsinteressen neu abgewogen werden, sagte Beckstein: "Dass der Intimbereich von Terroristen geschützt sein soll, ist für mich schwer erträglich."

Tut mir leid, Herr Beckstein, aber Sie sind in der Prüfung durchgefallen. Denn das Verfassungsgericht schützt nicht explizit den Intimbereich von Terroristen - sondern den Intimbereich der Bürger. Und der steht als schützenswertes Gut im Grundgesetz.

Warum wird eigentlich so einer nicht vom Verfassungsschutz beobachtet? Seine Verfassungsfeindlichkeit ist doch wirklich mehrfach dokumentiert ...

Novell will SCO an den Kragen

Und ihre Betrachtungen über die Rechtslage würden - wenn sie denn vor Gericht Bestand haben - SCO wirklich eine empfindliche Schlappe verpassen.

Der ganze SCO-Linux-Film ist ja recht spannend, aber ganz ehrlich: die Längen zwischen den Actionszenen sind doch ein bischen übertriebn

Pluto raus oder ein Neuer rein?

Astronomen haben ausserhalb der Pluto-Umlaufbahn einen Matschklumpen gefunden der mindestens so gross, warscheinlich aber sogar deutlich grösser als Pluto ist - Planet or Not, Pluto Now Has Far-Out Rival:

Astronomers announced yesterday that they had found a lump of rock and ice that was larger than Pluto and the farthest known object in the solar system. The discovery will probably rekindle debate over the definition of "planet" and whether Pluto still merits the designation.

Jetzt gehts drum ob Pluto seinen Planetenstatus verliert, oder der Neue auch Planet wird.

Wer mit PostgreSQL und Frontier arbeiten will, einfach die PostgreSQL Extension for Frontier installieren. Für Mac und Windows.

Vom Umgang mit Security

Unter ISS geht gegen Veröffentlichung des Vortrags über Cisco-Schwachstellen vor findet man eine Beschreibung wie sich Cisco und ISS Sicherheit vorstellen: massive Eingriffe in die Äusserungsrechte eines Vortragenden auf der Black-Hat-Konferenz. Ok, der war Ex-Mitarbeiter von ISS und hat wohl Informationen genutzt die er nicht veröffentlichen sollte - aber genau diese hirnrissige Geheimniskrämerei ist es ja, die Sicherheit unterminiert - denn das die Angreifer dieses Wissen früher oder später erlangen ist garantiert - wenn Sicherheitslücken existieren, werden sie früher oder später gefunden. Findet Sie jemand der darüber öffentlich berichtet, kann man sich wenigstens dagegen wehren und Gegenmaßnahmen einleiten. Wird die Veröffentlichung unterdrückt, ist der Leidtragende letztendlich der Endanwender - der keine Möglichkeit bekommt sich überhaupt abzusichern - und sei es im Notfall durch Wechsel zu einem anderen Routerhersteller.

Von daher ist es in der Tat so: weder ISS noch Cisco machen damit ein gutes Bild in der Öffentlichkeit. Im Gegenteil, deren Zensurversuche sind eigentlich nur noch ein Argument bei zukünftigen Produktentscheidungen sich gegen Cisco zu entscheiden - denn man kann deren Sicherheitsaussagen ja ganz offensichtlich nicht trauen.

Wer glaubte das ISO Zeitangaben einfach nur die YYYY-MM-TT HH:MM:SS.HS ist, vergesst es: International standard date and time notation. War ja klar, ist ja ein ISO Standard ...

Leichen im Keller

Jede Software hat sie - irgendwelche Leichen im Keller die anfangen zu stinken wenn man sie findet. Django leider auch. Und zwar die Behandlung von Unicode. Der automatisch generierte Admin in Django schickt immer XHTML und utf-8 raus an den Browser. Die Browser schicken daher auch utf-8 zurück. Jetzt gibt es aber Browser die bei solchen Sachen dann ein etwas anderes Format für die zu schickenden Daten benutzen - das sogenannte Multipart-Format. Dieses wird verwendet weil es die einzige garantierte Methode in HTTP-POST ist, bei der man einen Zeichensatz mitschicken kann.

Dummerweise parsed Django diese Multipart-POSTs mit dem email Modul von Python. Dieses produziert dann fleissig Unicode-Strings aus den als utf-8 markierten Parts. Was ja auch an und für sich korrekt ist - nur sind im Django-Source überall im Sourcecode str() Aufrufe verstreut. Und die krachen dann natürlich, wenn sie unicode vorgeworfen bekommen in dem Zeichen oberhalb von chr(128) drin sind.

Ich hab mir den Source mal angeguckt, der realistischste Ansatz dürfte sein in Django einfach generell dafür zu sorgen das auch Unicode-Ergebnisse dann wieder nach utf-8 gewandelt werden, so das intern nur normale Python-Strings benutzt werden. Das klappt auch soweit, aber es gibt dann noch Probleme mit manchen Datenbanken die bei Speicherung von utf-8 Inhalten das erkennen und dann beim Lesen der Inhalte wieder Unicode produzieren - SQLite ist so eine Datenbank.

Tja, das wird nicht ganz einfach zu beheben sein. Ich hab mich schon mal dran versucht, das ist ein ziemlich ekliges Thema und leider in Django überhaupt nicht berücksichtigt worden - und daher kracht es an allen Ecken und Enden. Mal gucken ob ich da nicht doch noch was brauchbares hinkriege ...

Was mir auch noch aufgefallen ist: Django schickt den Content-type nur über ein meta-Tag mit http-equiv raus. Das ist ein übler Hack, wesentlich besser wäre es wenn der Content-type korrekt als Header gesetzt wäre, dann kann auch nix schief gehen wenn z.B. Apache einen Default-Charset zufügen will. Und die Browser würden auch wesentlich reproduzierbarer reagieren.

Jedenfalls ist das wieder der typische Fall von amerikanischen Programmierern. Die erzählen einem gerne das man einfach nur auf Unicode und utf-8 wechseln soll wenn man von seinen Zeichensatzkodierungsproblemen berichtet, aber ich habe bisher noch keine Software eines amerikanischen Programmierers gesehen die Unicode korrekt gehandhabt hätte ...

Ansonsten gibts in Django noch so die eine oder andere Klinke - besonders nervig, weil nicht dokumentiert, aber leicht zu lösen: die Standard-Zeitzone in Django ist America/Chicago. Dazu muss man dann nur eine Variable TIME_ZONE mit 'Europe/Berlin' als Wert in sein settings-File schreiben und noch einen kleinen Patch anwenden, damit Django mit dem '-' als Zeitzonentrennzeichen klarkommt. Oh Mann, wenn Amerikaner schon mal Software schreiben ...

Irgendwie steigt im Moment gerade meine Motivation mir doch erstmal Ruby on Rails genauer anzugucken, schliesslich sind das Dänen die damit angefangen haben und die sollten zumindestens solche Sachen richtig hinkriegen (wenn nur nicht dieser nette automatische Administrationsteil von Django wäre - der ist es ja genau auf den ich es abgesehen hätte. Warum hat sowas nur keiner für ROR eingebaut, menno ...)

Update: Ich hab am entsprechenden Ticket zum Unicode-Problem einen Patch angehängt (einfach nach ganz unten scrollen) der erstmal das Problem halbwegs in den Griff bekommt - sofern man kein SQLite einsetzt, da SQLite immer Unicode-Strings zurückliefert und die dann auch wieder Stress machen. Aber zumindestens mit PostgreSQL funktionieren jetzt Umlaute in Django. Die Lösung ist nicht wirklich perfekt, aber zumindestens mit nur wenig Codeänderung reinzubringen. Eine richtige Lösung würde wohl grössere Codeumbauten erfordern.

Ein weiterer Patch hängt am Ticket zum Zeitzonenproblem, mit dem Patch kann man dann auch TIME_ZONE = 'Europe/Berlin' benutzen um die Zeitangaben zum Beispiel in der Änderungshistorie in der richtigen Zeitzone zu bekommen.

In solchen Momenten wünscht man sich commit-Rechte zu Django, um solche recht überschaubaren Patches selber reinstellen zu können

Noch ein Update: Adrian war im Chat gestern und heute und die Probleme mit Unicode sind weitestgehend raus. Nur mit SQLite gibts noch Stress, aber da hab ich den Patch schon fertig. Und die Zeitzonengeschichte ist auch behoben im SVN. Und er hat Unittests begonnen. Sehr sinnvoll, wenn man dann mal auf Dauer das ganze Framework sauber durchtesten kann nach einem Patch ...

Linkhaftung nach dem Heise-Urteil

Nach diesem Interview beim WDR gilt: "Jeder, der so einen Link setzt, ist dran":

Man muss eben sehr gut aufpassen. Aufgrund dieser neuen Urteile muss man sich überlegen: Auf wen setze ich einen Link? Früher hat man als Privatperson gesagt: 'Komm, ich hau da hundert Links hintereinander' und war ganz stolz. Heute muss man sich wirklich überlegen, ob der, auf den man einen Link setzt, wirklich vertrauenswürdig ist. Man muss diese Links dann auch in regelmäßigen Abständen gegenchecken und prüfen, was sich auf der gelinkten Seite tut.

Womit - wenn es denn tatsächlich so wäre - faktisch das privat betriebene Infoangebot tot wäre auf kurz oder lang, denn niemand kann seine ganzen Links durchprüfen. Ich hab hier fast 5000 Artikel im Blog, die werd ich garantiert nie alle durchgucken können ob da irgendwo irgendwas ist das irgendwem quer aufstösst.

Und so hat dieses Urteil wieder einen weiteren Nagel in den Sarg des Internet getrieben, nur weil Richter immer wieder diese Scheinrechte von Rechteabzockern höher als die freie Meinungsäusserung und die freie Berichterstattung einstufen

Wer wie ich in die Situation kommt das er die Unicode-Strings in PySQLite2 nicht mag und utf8 Bytestrings braucht: PysqliteFactories sind hier die Lösung, nicht Konverter. Denn Konverter müssten auf jede Spielart von varchar registriert werden die in Benutzung ist - die Row Factories hingegen sind da ziemlich agnostisch und praktisch. Und wenn man schon eine eigene Cursor-Klasse benutzt: diese einfach als Cursor Factory auslegen die dann mit self.row_factory der Instanz eine Row Factory verpasst.

Sysadmins Day

Lisa9 zeigt wie man anständig einem Sysadmin huldigt! Sogar DAU-tauglich mit bebilderter Anleitung

Abridged guide to HTTP Caching ist eine Beschreibung der wichtigsten Caching-Header in HTTP und wie sie verwendet werden sollten.

JSAN ist das für JavaScript was CPAN für Perl ist - ein zentrales Verzeichnis und Downloadbereich für JavaScript Sourcen und Paket.

Linux-VServer ist ein Kernel-Patch und ein Satz Utilities die es ermöglichen auf einer Basismaschine eine Reihe von virtuellen Linux-Kisten laufen zu haben deren Resourcen stark gegeneinander abgeschottet sind. chroot on steroids, oder am ehesten mit BSD Jails zu vergleichen. Interessant für Hosting-Projekte bei denen virtuelle Rootserver gefordert sind. Ist sogar in der aktuellen Debian drin.

Tor Network Status liefert eine Übersicht über Exit-Nodes im tor Netzwerk mit Trafficangaben, erlaubten Ports und IP-Daten. Nett. (gefunden über den Rabenhorst)

typo ist eine Blogsoftware für Ruby on Rails mit scheinbar schon recht weit ausgebauten Features. Speziell auch mit gutem Caching (produziert statische Seiten) für High-Traffic-Sites, bei denen dann Teile per JavaScript weiter dynamisch gehalten werden. Klingt danach das ich mir das nochmal angucken werde wenn mein ROR-Buch ankommt ...

Und die Erde ist doch eine Scheibe - von wegen. Dagegen ansingen!

Django, lighttpd und FCGI, zweiter Versuch

In meinem ersten Versuch mit diesem Zeug habe ich ein Beispiel gegeben, wie man Django-Projekte hinter lighttpd mit einfachen FCGI-Skripten, die in den Server integriert sind, ausführen kann. Ich werde ein wenig mehr über dieses Zeug erzählen, mit einer Möglichkeit, lighttpd und Django zu kombinieren, die viel mehr Flexibilität bei der Verteilung von Django-Anwendungen über Maschinen bietet. Dies ist besonders wichtig, wenn Sie mit hohen Lasten auf Ihren Servern rechnen. Natürlich sollten Sie den Django-Caching-Middleware verwenden, aber es gibt Zeiten, in denen selbst das nicht ausreicht und die einzige Lösung darin besteht, mehr Hardware an das Problem zu werfen.

Aktualisierung: Ich pflege meine Beschreibungen jetzt in meinem Trac-System. Siehe die lighty+FCGI-Beschreibung für Django.

Hinweis: Da Django sehr neue Software ist, habe ich keine Produktionserfahrungen damit. Daher handelt es sich hier eher um einen theoretischen Standpunkt, in den Wissen einfließt, das ich durch den Betrieb von Produktionssystemen für mehrere größere Portale gewonnen habe. Am Ende kommt es nicht so sehr darauf an, welche Software Sie verwenden - es kommt nur darauf an, wie Sie sie über Ihren Server-Farm verteilen können.

Um dieser Dokumentation zu folgen, benötigen Sie die folgenden Pakete und Dateien, die auf Ihrem System installiert sind:

  • [Django][2] selbst - derzeit aus dem SVN geholt. Folgen Sie den Setup-Anweisungen oder verwenden Sie python setup.py install.
  • [Flup][3] - ein Paket mit verschiedenen Möglichkeiten, WSGI-Anwendungen auszuführen. In dieser Dokumentation verwende ich den threaded WSGIServer.
  • [lighttpd][4] selbstverständlich. Sie benötigen mindestens die FastCGI-, die Rewrite- und die Accesslog-Module, diese werden in der Regel mit dem System kompiliert.
  • [Eunuchs][5] - nur erforderlich, wenn Sie Python 2.3 verwenden, da Flup socketpair in den vorkompilierten Servern verwendet und dies erst ab Python 2.4 verfügbar ist.
  • [django-fcgi.py][6] - mein FCGI-Server-Skript, das eines Tages Teil der Django-Distribution sein könnte, aber für den Moment einfach hier herunterladen. Legen Sie dieses Skript irgendwo in Ihren $PATH, z.B. /usr/local/bin und machen Sie es ausführbar.
  • Wenn das oben genannte aus irgendeinem Grund nicht funktioniert (vielleicht unterstützt Ihr System socketpair nicht und kann daher den vorkompilierten Server nicht verwenden), können Sie [django-fcgi-threaded.py][7] - eine Alternative, die den Threading-Server mit all seinen Problemen verwendet. Ich verwende es zum Beispiel auf Mac OS X für die Entwicklung.

Bevor wir beginnen, lassen Sie uns ein wenig über Serverarchitektur, Python und hohe Last sprechen. Die noch bevorzugte Installation von Django erfolgt hinter Apache2 mit mod python2. mod python2 ist eine recht leistungsfähige Erweiterung für Apache, die einen vollständigen Python-Interpreter (oder sogar viele Interpreter mit unterschiedlichen Namensräumen) in den Apache-Prozess integriert. Dies ermöglicht es Python, viele Aspekte des Servers zu steuern. Aber es hat einen Nachteil: Wenn der einzige Zweck darin besteht, Anfragen von Benutzern an die Anwendung weiterzuleiten, ist es eine ziemliche Übertreibung: Jeder Apache-Prozess oder Thread wird einen vollständigen Python-Interpreter mit Stack, Heap und allen geladenen Modulen enthalten. Apache-Prozesse werden auf diese Weise etwas fett.

Ein weiterer Nachteil: Apache ist einer der flexibelsten Server da draußen, aber im Vergleich zu kleinen Servern wie lighttpd ein Ressourcenfresser. Und - aufgrund der Architektur der Apache-Module - wird mod_python die vollständige Anwendung im Sicherheitskontext des Webservers ausführen. Zwei Dinge, die Sie in Produktionsumgebungen nicht oft mögen.

Ein natürlicher Ansatz ist also die Verwendung leichterer HTTP-Server und das Hinterlegen Ihrer Anwendung dahinter - unter Verwendung des HTTP-Servers selbst nur zum Servieren von Medien und unter Verwendung von FastCGI, um Anfragen vom Benutzer an Ihre Anwendung weiterzuleiten. Manchmal stellen Sie diesen kleinen HTTP-Server hinter einen Apache-Front, der nur mod_proxy (entweder direkt oder über mod_rewrite) verwendet, um Anfragen an den Webserver Ihrer Anwendung weiterzuleiten - und glauben Sie es oder nicht, dies ist tatsächlich viel schneller als das Servieren der Anwendung direkt mit Apache!

Die zweite Falle ist Python selbst. Python hat eine recht schöne Threading-Bibliothek. Es wäre also ideal, Ihre Anwendung als Thread-Server zu erstellen - weil Threads viel weniger Ressourcen als Prozesse verbrauchen. Aber das wird Sie beißen, wegen einer speziellen Funktion von Python: der GIL. Der gefürchtete globale Interpreter-Lock. Dies ist kein Problem, wenn Ihre Anwendung zu 100% Python ist - der GIL greift nur, wenn interne Funktionen verwendet werden oder wenn C-Erweiterungen verwendet werden. Schade, dass fast alle DBAPI-Bibliotheken mindestens einige Datenbank-Client-Code verwenden, der eine C-Erweiterung verwendet - Sie starten einen SQL-Befehl und das Threading wird deaktiviert, bis der Aufruf zurückkehrt. Keine mehreren Abfragen laufen ...

Die bessere Option ist also die Verwendung eines Fork-Servers, weil der GIL dann nicht greift. Dies ermöglicht einem Fork-Server, mehrere Prozessoren in Ihrer Maschine effizient zu nutzen - und so auf lange Sicht viel schneller zu sein, trotz des Overheads von Prozessen gegenüber Threads.

Für diese Dokumentation nehme ich einen dreischichtigen Ansatz zur Verteilung der Software: Die Front wird Ihr vertrauenswürdiger Apache sein, der einfach alles an Ihren projektspezifischen lighttpd weiterleitet. Der lighttpd hat Zugriff auf das Dokumentenstammverzeichnis Ihres Projekts und leitet spezielle Anfragen an Ihren FCGI-Server weiter. Der FCGI-Server selbst kann auf einem anderen Rechner laufen, wenn dies für die Lastverteilung erforderlich ist. Er wird einen vorkompilierten Server verwenden, weil es in Python ein Threading-Problem gibt, und er kann Multiprozessor-Maschinen nutzen.

Ich werde nicht viel über die erste Ebene sprechen, weil Sie dies leicht selbst einrichten können. Leiten Sie einfach Dinge an die Maschine weiter, auf der Ihr lighttpd läuft (in meinem Fall läuft der Apache normalerweise auf anderen Maschinen als die Anwendungen). Schauen Sie in der mod_proxy-Dokumentation nach, normalerweise ist es nur ProxyPass und ProxyPassReverse.

Die zweite Ebene ist interessanter. lighttpd ist ein bisschen seltsam in der Konfiguration von FCGI-Dingen - Sie benötigen FCGI-Skripte im Dateisystem und müssen diese mit Ihrem FCGI-Serverprozess verbinden. Die FCGI-Skripte müssen tatsächlich keinen Inhalt enthalten - sie müssen nur im Dateisystem vorhanden sein.

Wir beginnen also mit Ihrem Django-Projektverzeichnis. Legen Sie einfach ein Verzeichnis public_html dort hinein. Das ist der Ort, an dem Sie Ihre Mediendateien ablegen, z.B. das Admin-Media-Verzeichnis. Dieses Verzeichnis wird das Dokumentenstammverzeichnis für Ihren Projekt-Server sein. Stellen Sie sicher, dass Sie nur Dateien dort ablegen, die keine privaten Daten enthalten - private Daten wie Konfigurationen und Module sollten besser an Orten bleiben, die nicht vom Webserver zugänglich sind. Als Nächstes richten Sie eine lighttpd-Konfigurationsdatei ein. Sie werden nur die Rewrite- und die FastCGI-Module verwenden. Keine Notwendigkeit, ein Zugriffsprotokoll zu führen, dies wird von Ihrer ersten Ebene, Ihrem Apache-Server, geschrieben. In meinem Fall befindet sich das Projekt in /home/gb/work/myproject - Sie müssen dies an Ihre eigene Situation anpassen. Speichern Sie den folgenden Inhalt als /home/gb/work/myproject/lighttpd.conf


 server.modules = ( "mod_rewrite", "mod_fastcgi" )
 server.document-root = "/home/gb/work/myproject/public_html"
 server.indexfiles = ( "index.html", "index.htm" )
 server.port = 8000
 server.bind = "127.0.0.1"
 server.errorlog = "/home/gb/work/myproject/error.log"

fastcgi.server = (
"/main.fcgi" => (
"main" => (
"socket" => "/home/gb/work/myproject/main.socket"
 )
 ),
"/admin.fcgi" => (
"admin" => (
"socket" => "/home/gb/work/myproject/admin.socket"
 )
 )
 )

url.rewrite = (
"^(/admin/.*)$" => "/admin.fcgi$1",
"^(/polls/.*)$" => "/main.fcgi$1"
 )

mimetype.assign = (
".pdf" => "application/pdf",
".sig" => "application/pgp-signature",
".spl" => "application/futuresplash",
".class" => "application/octet-stream",
".ps" => "application/postscript",
".torrent" => "application/x-bittorrent",
".dvi" => "application/x-dvi",
".gz" => "application/x-gzip",
".pac" => "application/x-ns-proxy-autoconfig",
".swf" => "application/x-shockwave-flash",
".tar.gz" => "application/x-tgz",
".tgz" => "application/x-tgz",
".tar" => "application/x-tar",
".zip" => "application/zip",
".mp3" => "audio/mpeg",
".m3u" => "audio/x-mpegurl",
".wma" => "audio/x-ms-wma",
".wax" => "audio/x-ms-wax",
".ogg" => "audio/x-wav",
".wav" => "audio/x-wav",
".gif" => "image/gif",
".jpg" => "image/jpeg",
".jpeg" => "image/jpeg",
".png" => "image/png",
".xbm" => "image/x-xbitmap",
".xpm" => "image/x-xpixmap",
".xwd" => "image/x-xwindowdump",
".css" => "text/css",
".html" => "text/html",
".htm" => "text/html",
".js" => "text/javascript",
".asc" => "text/plain",
".c" => "text/plain",
".conf" => "text/plain",
".text" => "text/plain",
".txt" => "text/plain",
".dtd" => "text/xml",
".xml" => "text/xml",
".mpeg" => "video/mpeg",
".mpg" => "video/mpeg",
".mov" => "video/quicktime",
".qt" => "video/quicktime",
".avi" => "video/x-msvideo",
".asf" => "video/x-ms-asf",
".asx" => "video/x-ms-asf",
".wmv" => "video/x-ms-wmv"
 )

Ich binde den lighttpd nur an die localhost-Schnittstelle, weil in meiner Testumgebung der lighttpd auf demselben Host wie der Apache-Server läuft. In Multi-Server-Einstellungen werden Sie den lighttpd-Servern natürlich an die öffentliche Schnittstelle binden. Die FCGI-Skripte kommunizieren in dieser Einstellung über Sockets, weil in dieser Testumgebung ich nur einen Server für alles verwende. Wenn Ihre Maschinen verteilt wären, würden Sie die "host" und "port" Einstellungen anstelle der "socket" Einstellung verwenden, um mit FCGI-Servern auf verschiedenen Maschinen zu verbinden. Und Sie würden mehrere Einträge für die "main" Sache hinzufügen, um die Last der Anwendung auf mehrere Maschinen zu verteilen. Schauen Sie in der lighttpd-Dokumentation nach, welche Optionen Sie haben werden.

Ich richte zwei FCGI-Server für dies ein - einen für die Admin-Einstellungen und einen für die Haupt-Einstellungen. Alle Anwendungen werden durch die Haupt-Einstellungen FCGI weitergeleitet und alle Admin-Anfragen werden an den Admin-Server geleitet. Dies geschieht mit den beiden Rewrite-Regeln - Sie müssen eine Rewrite-Regel für jede Anwendung hinzufügen, die Sie verwenden.

Da lighttpd die FCGI-Skripte benötigt, um sie zu existieren, um den PATH_INFO an das FastCGI weiterzugeben, müssen Sie die folgenden Dateien berühren: /home/gb/work/myprojectg/public_html/admin.fcgi ``/home/gb/work/myprojectg/public_html/main.fcgi

Sie müssen keinen Code enthalten, sie müssen nur im Verzeichnis aufgeführt sein. Ab lighttpd 1.3.16 (zum Zeitpunkt der Abfassung dieser Zeilen nur in svn) können Sie ohne die Stubs für die .fcgi laufen - Sie fügen einfach "check-local" => "disable" zu den beiden FCGI-Einstellungen hinzu. Dann sind die lokalen Dateien nicht mehr erforderlich. Wenn Sie also diese Konfigurationsdatei erweitern möchten, müssen Sie nur einige sehr grundlegende Regeln beachten:

  • jede Einstellungsdatei benötigt ihren eigenen .fcgi-Handler
  • jeder .fcgi muss im Dateisystem berührt werden - dies könnte in einer zukünftigen Version von lighttpd verschwinden, aber für den Moment ist es erforderlich
  • die Lastverteilung erfolgt auf Ebene der .fcgi - fügen Sie mehrere Server oder Sockets hinzu, um die Last auf mehrere FCGI-Server zu verteilen
  • jede Anwendung benötigt eine Rewrite-Regel, die die Anwendung mit dem .fcgi-Handler verbindet

Jetzt müssen wir die FCGI-Server starten. Das ist eigentlich ganz einfach, verwenden Sie einfach das bereitgestellte django-fcgi.py-Skript wie folgt:


 django-fcgi.py --settings=myproject.work.main
 --socket=/home/gb/work/myproject/main.socket
 --minspare=5 --maxspare=10 --maxchildren=100
 --daemon

django-fcgi.py --settings=myproject.work.admin
 --socket=/home/gb/work/myproject/admin.socket
 --maxspare=2 --daemon

Diese beiden Befehle starten zwei FCGI-Serverprozesse, die die angegebenen Sockets zur Kommunikation verwenden. Der Admin-Server wird nur zwei Prozesse verwenden - dies liegt daran, dass der Admin-Server oft nicht der Server mit den vielen Hits ist, das ist der Hauptserver. Daher erhält der Hauptserver eine höhere als Standard-Einstellung für Reserveprozesse und maximale Kindprozesse. Natürlich ist dies nur ein Beispiel - passen Sie es an Ihre Bedürfnisse an.

Der letzte Schritt ist das Starten Ihres lighttpd mit Ihrer Konfigurationsdatei: lighttpd -f /home/gb/work/myproject/lighttpd.conf

Das war's. Wenn Sie jetzt entweder den lighttpd direkt unter http://localhost:8000/polls/ oder durch Ihren Front-Apache zugreifen, sollten Sie die Ausgabe Ihrer Anwendung sehen. Zumindest, wenn alles richtig gelaufen ist und ich nicht zu viele Fehler gemacht habe.

Eunuchs liefert ein paar Funktionen nach die unter Python 2.3 noch nicht verfügbar sind. Speziell socketpair und recvmsg/sendmsg sind da sehr wichtig - für Serverprogrammierung mit preforked Servern zum Beispiel.

Noch son Fragebogen

Aus meiner Mailbox von Lisa Sonnabend:

Im Rahmen meiner Abschlussarbeit am Institut für Kommunikationswissenschaft und Medienforschung der Ludwigs-Maximilians-Universität München führe ich eine Befragung unter Webloglesern zum Thema „Glaubwürdigkeit von Weblogs“ durch. Es handelt sich um eine der ersten wissenschaftlichen Untersuchungen zum Phänomen Weblogs in Deutschland.

Es soll geklärt werden, ob Weblogs in gewissen Punkten wie Fairness oder Unvoreingenommenheit bereits als ähnlich vertrauenswürdig und kompetent gesehen werden wie traditionelle Medien – und in welchen Punkten große Unterschiede herrschen. Darüber hinaus wird mit der Befragung untersucht, welche besonderen Qualitäten Weblogs aus Sicht der Rezipienten haben und welchen Stellenwert diese für die Nutzer spielen. Anhand der Ergebnisse soll anschließend eine Prognose über das zukünftige Gewicht von Weblogs in der Medienlandschaft gefällt werden.

Und ich soll den Link ins Blog packen, damit Leute dabei mitmachen. Nagut, mach ich das doch mal, auch wenn ich mich frage was für eine Kompetenz und Vertrauenswürdigkeit die alten Medien eigentlich haben sollen

Hier gehts zum Fragebogen

präventive Telefonüberwachung is nich

Denn das Verfassungsgericht erklärt präventive Telefonüberwachung für nichtig. Betrifft primär Niedersachsen, aber ähnliche Situationen gibt es auch in anderen Bundesländern. Gut wenn mal dem ganzen Überwachungsfetischismus ein Riegel vorgeschoben wird.

es gibt Tage da hasst mein Computer mich

Zum Beispiel wenn ich mit Flup spiele und statt des threaded Servers einen forked Server nehmen will. Und feststelle, das der dann aber die Funktion socketpair benötigt. Die aber dummerweise nur ab Python 2.4 verfügbar ist, welches zwar auf Debian Sarge da ist, aber dafür gibts in der Debian Sarge für Python 2.4 keinen Psycopg - welcher wiederum Voraussetzung für Django und PostgreSQL ist, weshalb ich mich überhaupt ja nur mit FastCGI beschäftige. PsycoPG selber installieren macht keinen Spaß, da man dafür nicht nur die PostgreSQL Header braucht, die normal installiert werden, sondern auch ein paar interne Header - also im Prinzip einen Build-Tree. Und dann braucht man noch die egenix-mx-base Header, die man nur für Python 2.3 kriegt, also müsste man das auch selber installieren. Backports aus der nächsten Debian geht auch nicht, da die gerade auf PostgreSQL 8.0 umbauen und Sarge ja noch 7.4 benutzt und ich nicht gleich das ganze System upgraden wollte. Und so dreht man sich im Kreis und kommt sich leicht verarscht vor vor lauter Abhängigkeiten und Versionskonflikten.

Und was macht man also als Lösung, weil der threaded Server dummerweise nur Segfaults im Psycopg produziert? Man nimmt den threaded Server, verbietet ihm das threaden und startet ihn über den spawn-fcgi vom lighttpd, oder direkt vom lighttpd. Was aber irgendwie auch wieder dämlich ist, da dann immer pro FCGI-Server 3 Threads rumgammeln, von denen 2 nur in der Prozessliste stehen und nix zu tun haben. Und das alles nur weil mod python2 (was für Django gebraucht wird) Apache2 voraussetzt, der wiederum mod perl2 voraussetzt, welches inkompatibel zum alten mod perl ist, weshalb bei mir eine ganze Reihe von meinen Sites nicht mehr laufen würden, würde ich auf Apache2 umstellen. Was ich eh nicht will, weil Apache2 mit mod python arschlangsam ist. Und schon wieder verarscht worden. Ich hätte mir echt einen sinnvolleren Beruf suchen sollen.

Wer nix kapiert hat: macht nix, ist Technik, ist nicht wichtig, wollte das einfach nur mal gesagt haben.

Higher-Order Perl ist ein Buch (zur Zeit Papier, aber soll demnächst frei im Netz lesbar sein) das sich mit higher order functions und Perl beschäftigt - könnte ganz interessant sein, Perl bietet da eine ganze Menge Features versteckt unter all den geschweiften Klammern und anderen Sonderzeichen ...

Django mit FCGI und lighttpd ausführen

Diese Dokumentation ist für einen grösseren Kreis als nur .de gedacht, daher das ganze in Neuwestfälisch Englisch. Sorry. Update: I maintain the actually descriptions now in my trac system. See the FCGI+lighty description for Django. There are different ways to run Django on your machine. One way is only for development: use the django-admin.py runserver command as documented in the tutorial. The builtin server isn't good for production use, though. The other option is running it with mod_python. This is currently the preferred method to run Django. This posting is here to document a third way: running Django behind lighttpd with FCGI.

First you need to install the needed packages. Fetch them from their respective download address and install them or use preinstalled packages if your system provides those. You will need the following stuff:

  • [Django][2] selbst - derzeit aus dem SVN. Folgen Sie den Setup-Anweisungen oder verwenden Sie python setup.py install.
  • [Flup][3] - ein Paket mit verschiedenen Möglichkeiten, WSGI-Anwendungen auszuführen. Ich verwende den threaded WSGIServer in dieser Dokumentation.
  • [lighttpd][4] selbstverständlich. Sie benötigen mindestens die FastCGI-, die Rewrite- und die Accesslog-Module, diese sind in der Regel mit dem System kompiliert.

Nach der Installation von ligthttpd müssen Sie eine lighttpd-Konfigurationsdatei erstellen. Die hier angegebene Konfigurationsdatei ist an meine eigenen Pfade angepasst - Sie müssen diese an Ihre eigene Situation anpassen. Diese Konfigurationsdatei aktiviert einen Server auf Port 8000 auf localhost - genau wie der runserver-Befehl dies tun würde. Aber dieser Server ist ein Server für die Produktion mit mehreren FCGI-Prozessen und einer sehr schnellen Medienauslieferung.


 # lighttpd-Konfigurationsdatei
 #
 ############ Optionen, die Sie wirklich beachten müssen ####################

server.modules = ( "mod_rewrite", "mod_fastcgi", "mod_accesslog" )

server.document-root = "/home/gb/public_html/"
 server.indexfiles = ( "index.html", "index.htm", "default.htm" )

 diese Einstellungen binden den Server an dieselbe IP und denselben Port wie runserver

server.errorlog = "/home/gb/log/lighttpd-error.log"
 accesslog.filename = "/home/gb/log/lighttpd-access.log"

fastcgi.server = (
"/myproject-admin.fcgi" => (
"admin" => (
"socket" => "/tmp/myproject-admin.socket",
"bin-path" => "/home/gb/public_html/myproject-admin.fcgi",
"min-procs" => 1,
"max-procs" => 1
 )
 ),
"/myproject.fcgi" => (
"polls" => (
"socket" => "/tmp/myproject.socket",
"bin-path" => "/home/gb/public_html/myproject.fcgi"
 )
 )
 )

url.rewrite = (
"^(/admin/.*)$" => "/myproject-admin.fcgi$1",
"^(/polls/.*)$" => "/myproject.fcgi$1"
 )

Diese Konfigurationsdatei startet nur einen FCGI-Handler für Ihre Admin-Angelegenheiten und die Standardanzahl von Handlern (jeder davon mehrthreadig!) für Ihre eigene Website. Sie können diese Einstellungen mit den üblichen ligthttpd FCGI-Einstellungen feinabstimmen, sogar externe FCGI-Erzeugung und Auslagerung von FCGI-Prozessen auf einen verteilten FCGI-Cluster nutzen! Admin-Medien-Dateien müssen in Ihr lighttpd-Dokumentenverzeichnis.

Die Konfiguration funktioniert, indem alle Standard-URLs so übersetzt werden, dass sie vom FCGI-Skript für jede Einstellungsdatei behandelt werden - um weitere Anwendungen zum System hinzuzufügen, würden Sie nur die Umschreiberegel für die /polls/-Zeile duplizieren und diese in choices oder was auch immer Ihr Modul heißt ändern. Der nächste Schritt wäre die Erstellung der .fcgi-Skripte. Hier sind die beiden, die ich verwende:


 #!/bin/sh
 # dies ist myproject.fcgi - legen Sie es in Ihr Docroot

export DJANGOSETTINGSMODULE=myprojects.settings.main

/home/gb/bin/django-fcgi.py

 #!/bin/sh
 # dies ist myproject-admin.fcgi - legen Sie es in Ihr Docroot

export DJANGOSETTINGSMODULE=myprojects.settings.admin

/home/gb/bin/django-fcgi.py

Diese beiden Dateien nutzen nur ein django-fcgi.py-Skript. Dies ist nicht Teil der Django-Distribution (noch nicht - vielleicht werden sie es einbeziehen) und der Quellcode ist hier gegeben:


 #!/usr/bin/python2.3

def main():
 from flup.server.fcgi import WSGIServer
 from django.core.handlers.wsgi import WSGIHandler
 WSGIServer(WSGIHandler()).run()

if name == 'main':
 main()

Wie Sie sehen, ist es eher einfach. Es verwendet den threaded WSGIServer aus dem fcgi-Modul, aber Sie könnten genauso leicht den geforkten Server verwenden - aber da lighttpd bereits Preforking durchführt, denke ich, dass es nicht viel Sinn hat, auf der FCGI-Ebene zu forken. Dieses Skript sollte sich irgendwo in Ihrem Pfad befinden oder einfach mit vollständig qualifiziertem Pfad wie ich es tue referenziert werden. Jetzt haben Sie alle Teile zusammen. Ich habe meine lighttpd-Konfiguration in /home/gb/etc/lighttpd.conf, die .fcgi-Skripte in /home/gb/public_html und das django-fcgi.py in /home/gb/bin. Dann kann ich das ganze mit /usr/local/sbin/lighttpd -f etc/lighttpd.conf starten. Dies startet den Server, preforkt alle FCGI-Handler und trennt sich vom tty, um ein richtiger Daemon zu werden. Das Schöne daran: Dies wird nicht unter einem speziellen Systemkonto, sondern unter Ihrem normalen Benutzerkonto ausgeführt, sodass Ihre eigenen Dateibeschränkungen gelten. lighttpd+FCGI ist recht leistungsfähig und sollte Ihnen eine sehr schöne und sehr schnelle Option zum Ausführen von Django-Anwendungen bieten. Probleme:

  • Unter hoher Last stürzen einige FCGI-Prozesse ab. Ich habe zunächst die fcgi-Bibliothek verdächtigt, aber nach etwas Herumspielen (Core-Debugging) stellte sich heraus, dass es tatsächlich der psycopg auf meinem System ist, der abstürzt. Sie könnten also mehr Glück haben (es sei denn, Sie laufen auch Debian Sarge)

  • Die Leistung hinter einem Front-Apache ist nicht das, was ich erwartet hätte. Ein lighttpd mit Front-Apache und 5 Backend-FCGI-Prozessen erreicht nur 36 Anfragen pro Sekunde auf meinem Rechner, während django-admin.py runserver 45 Anfragen pro Sekunde erreicht! (immer noch schneller als mod_python über apache2: nur 27 Anfragen pro Sekunde) Updates:

  • Die Trennung der beiden FCGI-Skripte funktionierte nicht richtig. Jetzt passe ich nicht nur auf die .fcgi-Erweiterung, sondern auf den Skriptnamen an, so dass /admin/ wirklich das myproject-admin.fcgi verwendet und /polls/ wirklich das myproject.fcgi verwendet.

  • Ich habe [ein anderes Dokument online][6], das mehr Details zur Lastverteilung enthält

flup: random Python WSGI stuff - eine Sammlung von WSGI-Server-Adaptern für FCGI, SCGI und Apache Jakarta 1.3 Protokolle sowie noch ein paar WSGI-Middlewares zur Authentifizierung, Komprimierung und Fehlerhandling.

Idiotische Patente die elfundelfzigste

Immer wenn man meint, man hätte schon das idiotischste Patent geseheh, kommts garantiert noch dämlicher - Microsoft will Smileys patentieren:

Der am Donnerstag veröffentlichte Patentantrag beschreibt ein Verfahren, um selbst erzeugte Emoticon-Bildchen als Zeichenfolgen zu kodieren, die sich in Textnachrichten einbetten lassen.

Leonardo ist ein CMS mit Blog und Wiki Modulen in Python. Im Moment noch recht schlicht als CGI, soll aber auf WSGI und Paste umgestellt werden und könnte dann ganz interessant als generelle CMS-Komponenten in einer WSGI-Lösung sein.

Python Paste ist ein Meta-Framework - ein Framework zur Erstellung neuer Web-Frameworks auf WSGI-Basis. Viele interessante Middleware-Module und eine Reimplementation von WebWare auf WSGI-Basis.

Scotland Yard erschiesst Unschuldigen

Mitlerweile ist ja klar das der von der britischen Polizei Erschossene unschuldig war. Und trotzdem: Scotland Yard verteidigt Kopfschuss-Praxis. Der frühere Scotland Yard Leiter:

"Es gibt nur einen sicheren Weg, einen Selbstmordattentäter zu stoppen, der davon überzeugt ist, seine Mission auszuüben - sein Gehirn sofort zu zerstören, vollständig", schrieb er in der Sonntagszeitung "News of the World". "Das heißt, ihn mit zerstörerischer Wucht in den Kopf zu schießen, ihn sofort zu töten."

Man muss dabei bedenken, das waren Polizisten in Zivil - eine Panikreaktion wenn eine Gruppe bewaffneter Menschen in Zivilkleidung hinter einem her sind ist ja wohl vorprogrammiert. Das dann als Begründung für einen gezielten Kopfschuss zu nehmen ist mehr als nur Zynismus.

Hinrichtungen auf Verdacht als Antwort auf Terror - damit wird der angebliche Schutz der Gesellschaft selber zum Terror und zur Gefahr für jeden Bürger. Die Unmenschlichkeit der Polizei-Vertreter in der Verteidigung dieser Praxis - Police chief 'sorry' over death - ist einfach nur abstoßend.

Seaside ist ein flexibles und sehr interessantes Web-Framework in Smalltalk. Tutorials hatte ich schon mal dazu gelinkt, aber das Framework selber noch nicht - jedenfalls nicht an seiner neuen Adresse. Läuft auf Squeak und Visual Works - und durch deren breite Verfügbarkeit fast auf allem das sich Computer nennen darf und eine TCP/IP-Verbindung zur Aussenwelt hat.

verpflichtetes Versicherungssponsoring durch den Staat?

Bundesaussenminister Fischer will eine verbindliche Riester-Rente - fragt sich natürlich der Leser was der Aussenminister damit zu tun hat, aber egal:

Bundesaußenminister Joschka Fischer hat sich für die Einführung einer verpflichtenden privaten Rentenversicherung ausgesprochen. "Das Rentensystem muss bezahlbar sein. Ich wünsche mir, dass die Riester-Rente endlich verbindlich eingeführt wird und wir die Menschen zur privaten Vorsorge ermutigen"

Soso. Zur privaten Vorsorge ermutigen. Dazu dann eine verpflichtende Teilnahme an der grössten Versicherungsabzocke aller Zeiten - der Riester-Rente, deren Renditen bescheiden sind und deren Zahlungsabsicherungen mehr als fragwürdig sind.

Man könnte natürlich auch einfach ein Modell einer Bürgerversicherung wählen, bei dem jeder in die staatlichen Sozialversicherungen einzahlt, ohne Besserverdienenden ein Schlupfloch nach draussen zu lassen - gerade im Rahmen der tollen Ideen wie Ich-AG und vermehrter Selbstständigkeit wird nämlich das Sozialversicherungssystem noch weiter ausgehöhlt. Aber das wäre ja eine intelligente Lösung. Die Staatlichen Sozialversicherungen haben nämlich den Vorteil das sie durch die Verfassung gewissen Regeln unterworfen sind - und der Staat sicherstellen muss, das auch die entsprechenden Leistungen erbracht werden.

Statt dessen wird also weiter die private Versicherungsbranche gesponsort und nach Fischers Vorstellungen auch noch mit ner Pflicht für den Bürger. Ja sowas bringt Aufschwung, sowas macht Sinn. Das die Bürger da nur über den Tisch gezogen werden und viele Modelle reine Beutelschneiderei sind und eine Auszahlungssicherheit in keinster Weise gegeben ist, ignorieren wir einfach mal.

Eins ist sicher: bei der Idiotie unserer Politiker gibts demnächst viel zu verdienen in der Versicherungsbranche. Die dann vermutlich nichts besseres zu tun hat als unsere dann privaten Zwangsrenten an der Börse zu verzocken und an Hedgefonds zu verhökern.

Verrückter Vinokourov ...

... schnappt der einfach den Sprintermannschaften den Sieg in Paris vor der Nase weg. Damit hat nun wirklich niemand gerechnet. Erst greift er sich noch zwei Sekunden Gutschrift im Kampf um die Gesamtwertung und da den 5. Platz ab und dann will er einfach sich nicht einreihen und den Sprintern das Feld überlassen. Klasse Aktion, solche Überraschungen mag ich

Da wird Otto wieder schäumen

Owl Content

Jetzt muss er warscheinlich gegen die EU wettern, denn die EU-Kommission pocht auf Unabhängigkeit der Datenschutzbehörden:

Die EU-Kommision hat gegen Deutschland ein Vertragsverletzungsverfahren wegen Missachtung der EU-Datenschutzrichtlinie eingeleitet. Sie beanstandet, dass die Aufsicht über die Gewährleistung der Privatsphäre hierzulande in staatlicher Hand ruht. Die "derzeitige Organisation der für die Überwachung der Datenverarbeitung im nicht-öffentlichen Bereich zuständigen Kontrollstellen" sei "nicht mit Gemeinschaftsrecht vereinbar", heißt es in einem heise online vorliegenden Schreiben der Generaldirektion für Justiz, Freiheit und Sicherheit.

In wieweit man in Anbetracht der Bestrebungen zu längeren Speicherzeiten für Komunikationsdaten innerhalb der EU viel auf das plötzliche Eintreten der EU-Kommission für den Datenschutz geben sollte ist eine ganz andere Sache ...

GNU Modula-2 war mir bisher unbekannt. Schön das sich Modula-2 auch in der GNU-Compilerfamilie wiederfindet. Auch wenn Modula-2 für mich nur noch historisches Interesse hat - dynamische Sprachen wie Python sind mir einfach wesentlich lieber. Aber es gab mal Zeiten als ich noch fleissig in Modula-2 programmiert habe.

MochiKit ist eine JavaScript-Bibliothek mit einer ganzen Reihe von Erweiterungen für JavaScript. Vor allem Iteratoren, vernünftige funktionale Konzepte (filter, map, partial application), aber auch eine ganze Reihe neuer Ideen, wie zum Beispiel eine sehr nette AJAX-Integration. Sieht schon ganz nett aus, muss ich mal mit rumspielen.

Spitzenköche kämpfen für Linda - und wollen eine Unterschriftenaktion starten. Hey, meine Unterschrift habt ihr dafür. Schliesslich bin ich bei Kartoffeln extrem wählerisch. Und nein, da reichts nicht das die neue Kartoffelsorte einen Namen aus Startrek Voyager trägt

Von Pechvögeln und Favoriten

Naja, heute war eines auf jeden Fall ganz klar (neben der Tatsache das Armstrong halt immer noch besser als Ullrich fährt, auch beim Zeitfahren): Rasmussen ist der Pechvogel des Tages. Zwei Stürze, 5 Defekte und über 7 Minuten eingetütet bekommen, das tut weh. Zum Glück ist er angekommen und er kann sich trösten: auch heute bekommt er ein gepunktetes Trikot übergestreift.

Die nächste Tour zeichnet sich mit den Favoriten auch ab: Ullrich und Basso ganz oben in der Liste. Vinokourov sicherlich auch ein Favorit, aber definitiv mit deutlichem Abstand. Mag ja sein das irgendwann ein neuer Fahrer nachkommt - aber die drei sind auf jeden Fall beim Kampf um den Sieg dabei.

Interessanter wird es allemal wenn Armstrong nicht mehr antritt - die Favoriten fürs nächste Jahr liegen definitiv deutlich enger beieinander und damit dürften die Kämpfe auch wieder spannender werden. Ullrich und Vinokourov klar die deutlich stärkeren Zeitfahrer, Basso der deutlich bessere Bergfahrer - das wird mit Sicherheit spannend.

Nur eins kapier ich auch am Ende der Tour nicht: wieso T-Mobile den Zabel nicht mitgenommen haben. Diese Pfeifen.

Und wieder mal Django

Django - das kommende Webframework für Python - hat jetzt SQLite 3 Support. Damit ist eine Installation einer Entwicklungsumgebung für Django-Projekte jetzt extrem simpel geworden: Python 2.3 oder Python 2.4 muss da sein und ansonsten noch SQLite3 und PySQLite2. Auf dem Mac ist also im Prinzip schon alles da, ausser PySQLite2 - letzteres kann man sich aber von www.pysqlite.org holen und einfach mittels sudo python setup.py install installieren. Und schon kann man mit Django loslegen und die Tutorials durcharbeiten. Kein Apache mehr nötig, kein PostgreSQL (zwar die netteste aller SQL-Datenbanken, aber trotzdem für eine Entwicklungsumgebung auf Notebook manchmal einfach Overkill) und vor allem nicht psycopg - dessen Installation leider einen fast vollständigen PostgreSQL-Source-Tree erfordert. Es gibt also keine Ausrede für Pythonistas mehr sich nicht mit Django zu beschäftigen

Internet-Pranger der US-Strafverfolgungsbehörden

Scheiss auf Persönlichkeitsrechte, im Land der Mutigen und Freien stellt das US-Justizministerium eine Sexualstraftäter-Datenbank ins Netz. Und wer glaubt das wär ja nicht so schlimm, trifft ja nur Vergewaltiger und Pädophile:

Die Online-Aktivitäten der US-amerikanischen Strafverfolger richten sich nicht nur gegen verurteilte Straftäter. Die Polizei von Chicago hat kürzlich eine Site in Betrieb genommen, auf der Personen abgebildet und mit Namen veröffentlicht werden, die der "Unterstützung der Prostitution" verdächtigt werden. Auf der Site findet sich der Hinweis, dass die aufgeführten Personen als unschuldig gelten, bis ein Gericht ihre Schuld festgestellt hat.

Toll, nicht war? Hängen wir dein Bild einfach mal an den Pranger, den kleinen Nebensatz wird der Lynchmob sicherlich lesen bevor er das Seil auspackt und mit deinem Arsch zum nächsten Baum zieht. Und sowieso, Sexualstraftäter kann man als Begriff ja garnicht weit genug fassen ...

Grosser Lauschangriff auch in Sachsen Verfassungswidrig

Owl Content

Sachsens Verfassungsgerichtshof kippt in Teilen den "Großen Lauschangriff" und natürlich fühlen die Poltiker sich trotzdem bestätigt, es müssen ja nur die Gesetze geändert werden - sorry, aber das sehe ich anders. Die Denke muss geändert werden und es ist schade das die Verfassungsrichter nicht da deutlicher werden.

Apache modauthtkt ist ein Framework für Single-Signon in Apache-basierten Lösungen über Technikgrenzen (CGI, mod_perl und was sonst noch so existiert) hinweg. Müsste ich mir mal angucken, könnte für mich interessant sein.

Doohan alias Scotty gestorben

Scotty wurde zum letzten Mal hochgebeamt - und diesmal wird ihn wohl keiner aus dem Musterpuffer seines Transporters rekonstruieren können. Trinken wir ein Gläschen Scotch auf ihn.

Wie die BWLer unter Bertelsmann in die Bildungspolitik einziehen

Bei Telepolis gefunden: TP: Durchsetzung von Controlling und Ranking auf allen Ebenen:

Wäre ein kritischer Ökonom zum Kongress geladen gewesen, er hätte die Strategie der Bertelsmänner wohl so formuliert: Demokratische Entscheidungsfindung und offene Diskussion wird ersetzt durch Steuerungsverfahren aus der neueren Betriebswirtschaftslehre. Überzuckert wird alles mit dynamischen Anglizismen aus dem Marketing-Babbel, dahinter aber stecken oft Ideen aus dem BWL-Fach Controlling. Früher sprach man prosaischer vom Rechnungswesen/Interne Revision, meinte aber dasselbe: die innerbetriebliche Steuerung und Kontrolle von Produktionsprozessen. Die erfolgt mittels Nutzwertanalyse, Erfolgsrechnung, Budgetierung, Profit Center, Kennzahlen für alles und jedes etc.

Meine persönliche Abneigung gegen die BWL als meines Erachtens viel zu kurzsichtige Vision von Markt sollte ja mitlerweile bekannt sein. Die Verknüpfung mit einem recht scheinheilig agierenden Grossverlagshaus macht das ganze aber dann wirklich brisant - denn solche Konzerne haben nunmal in erster Linie eigene wirtschaftliche Interessen und sollten daher aus Bildungspolitischen Diskussionen rausgehalten werden, ganz besonders sind sie definitiv die falschen um sie in bildungspolitische Entscheidungsfindungen als Berater einzubinden. Aber im Zuge der Privatisierungsgeilheit der Politiker werden immer wieder solche Böcke geschossen - verbunden mit den dabei automatisch entstehenden Marketinglügen die von solchen Unternehmen dann zur Festigung der eigenen Route aufgebaut werden (wie z.B. die im Text zitierte Umfrage über Studiengebühren, bei der einfach der Weg des kostenlosen Studiums ausgeschlossen wurde - und dann behauptet wurde, das Studenten mehrheitlich für Studiengebühren wären).

Das grösste Problem bei dieser engen Verknüpfung mit der Wirtschaft - egal ob jetzt Bertelsmann in der Bildungspolitik oder andere Firmen in anderen Bereichen - ist die fehlende demokratische Kontrolle. Politiker werden noch rudimentär kontrolliert, öffentliche Einrichtungen sind durch das neue Informationsgesetz zur Offenlegung vieler Bereiche gezwungen, aber Entscheidungsfindungen in privatwirtschaftlichen Einrichtungen unterliegen diesen Kontrollen nicht. Wenn Politiker sich aber zum Beispiel auf Untersuchungen aus der Wirtschaft berufen wird man über das Informationsfreiheitsgesetz zwar bis zu dem Punkt kommen - das die Entscheidung auf einer Studie von Institut Sowieso basiert - aber über die Struktur und den eigentlichen Inhalt der Studie erfährt man unter Umständen garnichts. Und damit ist die Kontrolle durch die Bevölkerung stumpf ausgehebelt.

Gerade bei der Wichtigkeit der Bildungspolitik muss meines Erachtens jeder Einfluss von Wirtschaft und Industrie ausgeschlossen werden. Völlig egal was diese fordern - sie haben in der politischen Gestaltung der Bildungspolitik nichts verloren. Aber leider verkaufen unsere Politiker die politische Steuerung immer wieder an privatwirtschaftliche Institute, anstatt die Arbeit selber zu machen. Und sie verkaufen damit unsere Zukunft und unsere Souveränität als Gesellschaft an die Wirtschaft.

EU-Haftbefehl verfassungswidrig

Das Bundesverfassungsgericht fällt eine Entscheidung zum EU-Haftbefehl - und die fällt negativ aus. Der EU-Haftbefehl verstösst gegen das Grundgesetz. Und unsere Regierung? Bezeichnet das als Schlag gegen die Terrorbekämpfung und mokiert sich über die Bürokratisierung. Bitte was? Das Grundgesetz einzuhalten ist keine Prinzipienreiterei und Bürokratisierung, sondern eine Notwendigkeit. Aber das interessiert Frau Zypries genausowenig wie die Entscheidung des Bundestags gegen die Softwarepatentrichtlinie - und sie kündigt gleich eine Gesetzesinitiative an, die den EU-Haftbefehl wieder möglich macht.

Ich finds zum Kotzen. Wohlgemerkt, der Verdächtige ist in Deutschland nicht überführt oder verurteilt worden - die Abschiebung/Auslieferung basiert allein auf einem EU-Haftbefehl aus Spanien. Und es ist nicht so das nicht versucht worden wäre ihn hier zu verurteilen - es reichte einfach nur nicht, was vorgelegt wurde.

Also wird einfach mal die Unschuldsvermutung ausgehebelt und das Grundgesetz als alberne Bürokratie abgetan - alles im Namen der Terrorbekämpfung.

Wer schützt uns eigentlich vor den Wahnsinnigen in Berlin?

Jython 2.2 in der Mache

Die Jython Webseiten geben noch nix her, aber in der Mailingliste gabs vor ein paar Tagen eine Info das eine neue Alpha für Jython 2.2 raus ist - und zwar diesmal (war ja schon Ende 2004 mal so weit) eine die funktioniert. Viele Features der neueren Python-Versionen sind drin, auch Generatoren/Iteratoren. Von daher ist es nicht identisch mit Python 2.2, sondern eher ein gutes Stück auf den Weg zu Python 2.3 von den Features her. Da der Entwickler mit OS X arbeitet und dort entwickelt ist es relativ problemlos dort zu installieren.

Zur Installation, da das nirgendwo explizit erwähnt wird:


java -jar [jython .version.elend.langer.name.jar]

Dann kommt ein grafischer Installer der alles auf die Platte kippt. Dann in dem Zielverzeichnis noch zusätzlich folgende Befehle eingeben:


chmod 755 jython
chmod 755 jythonc

Dann sind die beiden (jython ist der Interpreter und jythonc ein Compiler) auch aufrufbar und es kann losgehen. Beim ersten Start von jython wird eine ganze Reihe von Systempaketen aktiviert, also nicht wundern über die vielen Meldungen vom sys-package-mgr.

Wer Jython nicht kennt: das ist eine Reimplementierung von Python auf der Java Virtual Machine. Dadurch lassen sich sehr elegant alle Java-Libraries benutzen und durch die interaktive Shell von Jython lässt sich auch mit Java-Klassen interaktiv spielen. Sehr schön um mal schnell Sachen auszuprobieren. Aber natürlich auch sehr schön um zwar die Portabilität von Java zu haben, aber nicht die kranke Sprache

Und es ist halt einfach witzig so Sachen wie die hier zu machen:


Jython 2.2a1 on java1.4.2_07 (JIT: null)
Type "copyright", "credits" or "license" for more information.
>>> import java.lang
>>> dir(java.lang.Number)
['byteValue', 'doubleValue', 'floatValue', 'intValue', 'longValue', 'shortValue']
>>> import java
>>> dir(java)
['__name__', 'applet', 'awt', 'beans', 'io', 'lang', 'math', 'net', 'nio', 'rmi', 'security', 'sql', 'text', 'util']
>>> ```

Erste Django Tutorials online

Die Django-Programmierer legen mit den Tutorials los. Das erste Tutorial beschäftigt sich primär mit der Erstellung des Datenbankmodells und des Grundcodes für die zu verwaltenden Objekte und das zweite Tutorial beschäftigt sich mit der automatisch generierten Administrationsoberfläche. Sehr nett, das ganze.

Das System ist natürlich stark auf Content-Erstellung und Verwaltung ausgerichtet - aber trotzdem allgemein genug, so das man es auch für anders gelagerte Inhalte nutzen kann. Die ganze Administration wird automatisch aus dem Objektmodell und einigen Hints erstellt, orientiert sich also immer an den realen Daten im System. Und die Default-Optik ist auch recht ansprechend.

Die Serverintegration geschieht einfach über mod python - also über den Apache. Was ebenfalls ein Vorteil ist, denn mod python bietet sehr hohe Performance schon von Hause aus. Und für heftigere Fälle gibts ja das Caching in Django. Ich muss sagen, was ich bisher von Django sehe gefällt mir ausgesprochen gut.

Ein wichtiger Hinweis fehlt in der Installationsanleitung: Apache2 ist zwingend nötig, und daher auch ModPython in der entsprechenden Version. Mac OS X liefert aber nur Apache 1.3 und viele andere Server haben auch nur den 1.3er Apache zur Verfügung, da hat Django also noch ein echtes Manko.

Wer übrigens auf Debian von Apache zu Apache2 upgraden will: wenn mod perl im Einsatz ist, vergesst es. Das mod perl2 für den Apache2 in der Debian Sarge ist kompletter Schrott - als ob die API-Änderungen in mod perl2 im Vergleich zum alten mod perl nicht schon nervig genug wären. Im Prinzip kriegt man damit keine Perl-Module mehr so einfach zum Laufen.

Update: Übrigens ist gerade im Subversion zu Django eine Menge Aktivität drin um die Pflicht für Apache zu beseitigen. Ein einfacher Entwicklungsserver ist schon drin, man wird also in Zukunft für erste Spielereien keinen Apache mehr benötigen. Und auch das Deployment könnte man damit auf Dauer auch auf andere Beine stellen - z.B. FCGI hinter lighttpd.

Update 2: Das dritte Tutorial ist da und beschäftigt sich mit der Sicht für den Besucher. Die haben ein ganz schön heftiges Tempo im Moment bei Django.

Erster Etappensieg für Gerolsteiner in der Tour

Wow. Das war ne Etappe - die Top-Fahrer haben klar gezeigt wie das Leistungsniveau liegt. Armstrong und Basso mit den besten Beinen, Ullrich sehr stark und damit auch eine klare Ansage an Klöden und Vinokourov, wer der Kapitän ist. Aber definitiv nicht stark genug für Armstrong. Ob Basso Armstrong knacken kann weiss ich auch nicht - heute haben ihm seine Helfer doch deutlich gefehlt, Sastre und Julich fehlt halt doch das letzte Stückchen Kraft.

Aber die absoluten Stars sind Gerolsteiner. Zum Einen natürlich die immer noch super Platzierung von Leipheimer, ihrem Kapitän. Aber den Vogel abgeschossen hat Georg Totschnig mit seinem Etappensieg. Dem ersten in der Tour für Gerolsteiner überhaupt und auch dem ersten Etappensieg in der Tour für Totschnig. Ich hab schon lang keinen Fahrer und sportlichen Leiter mehr sich dermaßen über einen Sieg freuen sehen wie Totschnig und Holczer. Klasse Leistung, dicke Gratulation an die beiden dafür.

Übrigens ist Gerolsteiner gerade der Typo3-Server (jau, Gerolsteiner benutzt Open Source) gestorben - könnte das vielleicht am Etappensieg und den vielen neugierigen Besuchern liegen?

Foundations of Python Network Programming ist ein relativ neues Buch über Netzwerkprogrammierung mit Python. Behandelt alle möglichen Ecken der Netzwerkprogrammierung die man sich denken kann - ziemlich klasse der erste Eindruck. Ich kenn zwar die meisten Sachen schon irgendwoher, aber so kompakt in einem Buch ist das trotzdem nett zum Nachlesen. Zusammen mit Dive Into Python würde ich die beiden als das ideale Gespann zum Python lernen sehen.