Der Patrick hat mich gebeten, Dinge zu Django aufzuschreiben, die über den grundlegenden Workshop, den ich neulich gehalten habe, hinausgehen. Ich weiß nicht so ganz, was ich dazu schreiben soll und wie viel davon tatsächlich interessant ist, aber ich habe einfach mal den Code meiner abgeschlossenen und laufenden Django-Projekte durchforstet, und dabei aufgeschrieben, was mir so schien, als könnte es anderen Entwicklern nützlich sein. Ich habe das ganze sehr lose in verschiedene Abschnitte gegliedert, aber ansonsten nicht weiter sortiert.

Generell

Benutzt Python 3. Bitte. Und Django 1.7+. Danke. Und lest mehr in der Doku, sie ist fast vollständig lesenswert. :-)

Projektstruktur

Django bietet die Möglichkeit, das Projekt in sogenannte Apps aufzuteilen. Die Idee dahinter ist hauptsächlich die der Wiederverwendbarkeit von Apps, die ich in der Realität bisher eher für unrealistisch halte, aber dennoch kann es sinnvoll sein, diese Möglichkeit zu nutzen. Ich habe in verschiedenen Projekten bisher verschiedene Ansätze ausprobiert, angefangen bei einem monolithischen Modell mit einer gigantischen App, sowie zusätzlichen, "kleinen" Apps für Meta-Funktionen wie Analyse und Statistik, bis hin zu einer Aufteilung in mehrere austauschbare Apps (z.B. eine für Backend und eine für Frontend), die nicht voneinander abhängen dürfen und einer App mit gemeinsamen Funktionen und Models, von der alle anderen abhängen. Verschiedene Apps für verschiedene Features sind sicher oft sinnvoll, bei mir aber meist nicht realistisch, da die Features zu stark zusammenhängen und ineinander integriert sind.

Welcher Ansatz sinnvoll ist, hängt wohl sehr vom Projekt ab, aber ich fahre bis jetzt mit letztere Aufbau am besten.

Standardmäßig legt Django pro App eine views.py, eine urls.py, ein eine tests.py und eine models.py an. Während man bei urls und models oft sehr lange mit einer Datei auskommt, ist es bei views und tests nützlich zu wissen, dass es Django nicht stört, wenn man daraus ein Subpackage macht und das in mehrere Dateien aufteilt.

Debugging

Zum Debugging empfehle ich die allseits bekannte Django Debug Toolbar, die mir nicht nur beim Debugging selbst sehr nützlich ist, sondern vor allem auch dafür, das ORM im Auge zu behalten: Wenn man unachtsam Code schreibt, passiert es einem leider leicht, dass man extrem viele Datenbankqueries produziert. Das Problem fällt meist in der Entwicklungsphase, wenn man mit kleinen Testdatensätzen arbeitet, oft nicht auf aber verursacht dann riesige Last, sobald man in Produktion geht. Faustregel: Jede Aktion sollte eine konstante (bzw. konstant nach oben beschränkte) Anzahl Datenbankqueries verursachen, die unabhängig von der Anzahl der Datensätze sein sollte.

In Produktion ist dann, wenn User sich beschweren, django-impersonate ein nützliches Tool, um Fehler nachzuvollziehen.

Statische Dateien

Bei jedem größeren Projekt wollt ihr wahrscheinlich statt CSS-Code lieber LESS oder SASS schreiben. Der django-compressor regelt das für euch genauso, wie er CSS und JavaScript komprimieren kann. Im Entwicklungsmodus tut er das live und transparent, in Produktion kann man ihn vorkompilieren lassen.

Models

Schaut euch die Dokumentation zu models.ForeignKey an und behaltet im Kopf, dass die Standardeinstellung für on_delete auf CASCADE steht: Wenn ihr ein referenziertes Objekt löscht, werden alle referenzierenden Objekte mitgelöscht. Das kann einem den Kopf kosten (für euch getestet) und man ist in fast allen fällen mit PROTECT oder SET_NULL besser beraten.

Authentifizierung

Seit einiger Zeit macht Django es recht einfach möglich, eigene User-Models statt dem mitgelieferten django.contrib.auth.models.User zu verwenden. Macht von dieser Möglichkeit früh Gebrauch – wenn der Bedarf erst später entsteht, ist eine Migration im Produktivbetrieb zwar möglich, aber ziemlich aufwändig1.

Signals

Das Signal-Framework von Django ist viel mächtiger als es auf den ersten Blick aussieht. Hierzu gibts wahrscheinlich irgendwann einen Vortrag oder Extra-Blogpost von mir.

Hintergrundprozesse

Es gibt fast keinen Fall, in dem es gerechtfertigt ist, den User auf eine Antwort warten zu lassen. Man sollte daher tunlichst vermeiden, irgendetwas, das länger dauern kann, in einem View zu tun. Ich verwende Celery als Task Queue für möglichst alles, was länger dauern kann oder von externen Erreichbarkeiten abhängt, sei es der Export vieler Daten oder das bloße Versenden von E-Mails.

Für Cronjob-artige Dinge verwendete ich früher django-cron, aber muss mich nach einer Alternative umsehen oder es auf Python 3 portieren.

Templates

Es ist eine Überlegung wert, Djangos Template Engine durch Jinja2 zu ersetzen. Ich habe dies in einem Projekt getan, weil ich Dinge abbilden musste, die in Djangos TE sehr umständlich gewesen wären und werde es wohl noch öfter tun, wenn Django 1.8 released ist, das bedeutend bessere Unterstützung für externe Template Engines bieten wird.

Views

Ich habe zu Beginn meiner Arbeiten mit Django vernachlässigt, wie mächtig Class-based views sind und sie viel zu wenig verwendet. Ich kann euch nur empfehlen, euch die ganz genau anzuschauen.

Unit Tests

Wenn ihr wirkliche Interface-Tests machen wollt, dann lässt sich Django mithilfe des StaticLiveServerTestcase recht gut mit Selenium verbinden2.

Lokalisierung

Auch wenn ich noch nicht in den zweifelhaften Genuss kam, ein mehrsprachiges Projekt in Produktion zu bringen, kann ich den Tipp geben, dass man das, wenn man es je tun möchte, gar nicht früh genug einplanen kann.


  1. Ja, ich habe auch das für euch getestet. 

  2. In der Dokumentation gibt es ein Beispiel.