Springe zum Hauptinhalt

Webtechnologien

Django

Die erste Django Version wurde im Jahr 2005 veröffentlicht. Das Web-Framework entstand aus der Not heraus Webanwendungen in extrem kurzer Zeit zu programmieren. Das Team von "The World online" war für die Wartung von verschiedenen lokalen Nachrichtenseiten zuständig. Sie stellten schnell fest, dass sie viele Dinge immer und immer wieder implementierten. Nach und nach entwickelte sich ein Framework, welches sie dann unter der BSD-Lizenz veröffentlichten. Die Tatsache das Django ursprünlich in einem journalistischem Umfeld entstand, fällt heute jedoch kaum noch auf. Obwohl immer noch viele Zeitungen ihren Online Auftritt mit Django realisieren. Die Möglichkeiten gehen weit darüber hinaus. Eine vielzahl von Beispielen kann man auf dieser Seite finden: http://www.djangosites.org/.

Eine Django Anwendung/Webseite besteht dabei aus mehreren Applikationen. Das sorgt dafür, dass man Applikationen in anderen Anwendungen wiederverwenden kann. So lohnt es sich oft, für bestimmte einsatzzwecke die Applikation nicht selbst zu schreiben, sondern zu schauen ob sich nicht schon jemand die Arbeit gemacht hat und das Ergebnis veröffentlicht hat. Das ist öfter der Fall als man meinen könnte, alleine eine Suche auf github bringt mehr als 7000 Ergebnisse. Viele dieser Anwendungen für oft benötigte Einsatzzwecke sind sehr gut gewartet und werden stetig weiterentwickelt. Sucht man etwas bestimmtes oder braucht Hilfe beim Einsatz einer bestimmten Anwendung hilft oft ein Blick in die Frage-Antwort-Webseite stackoverflow.com.

Djangos MVC Variante

Django verfolgt ein an das MVC-Modell angelehntes Entwurfsmuster. Das heißt, es erfolgt eine Trennung zwischen dem Modell, den Daten und einer Repräsentation dieser Daten. Auch hier sieht man das sich Django nicht dogmatisch an bestimmte Entwurfsmuster hält. Eine Django Applikation unterteilt sich in 4 Teile:
  • dem Model
  • dem View
  • dem Template
  • einer Beschreibung welche URL zu welchem View gehört

Der Hauptvorteil eines solchen Entwurfsmuster ist die Tatsache, dass man einzelne Teile tauschen kann ohne die anderen zu beeinflussen. So können unterschiedliche Spezialisten gleichzeitig an einem Projekt arbeiten. Sie müssen sich "nur" über die Schnittstellen einig werden. So kann z.B. die URL-Struktur verändert werden ohne das der Code der eigentlichen Views geändert werden muss oder man kann das Template verändern ohne das die Views davon betroffen sind.

View

Views sind in Django dafür zuständig die Anfragen an eine bestimmte URL zu verarbeiten. Eine einfache view.py sieht z.B. so aus?

from django.http import HttpResponse
import datetime

def hello_world(req):
  html = Hello world, it is %s. % datetime.datetime.now()
  return HttpResponse(html)

Wie man sieht, ist das View ganz normales Python, welches den HTML-Code der Seite "zusammensetzt" und am Ende ausgibt. Man kann alle Python Bibliotheken benutzen, wie man es auch ohne Django machen würde. Wir werden von dieser Funktionalität noch viel Gebrauch machen.

Die in der views.py definierten Funktionen werden im nächsten Schritt mit einer URL verknüpft. Alle Daten wie POST und GET Variablen, Session Cookies,... werden in der Variable req an die Funktion übergeben.

URLs

Um die oben stehende Funktion mit einer URL zu verknüpfen müssen wir diese Verbindung in der urls.py definieren.

from django.conf.urls.defaults import patterns, include, url
from start.views import hello_world

urlpatterns = patterns('',
  url(r'^hello_world/$', hello_world)
)

Die URL wird mit einem regulären Ausdruck angegeben. Es folgt der Name der einzubindenden Funktion.

Templates

In dem Beispiel oben haben wir den HTML Code der Seite direkt im Code des Views als einfachen String eingegeben. Das ist natürlich nicht wirklich sinnvoll. Um eine Trennung zwischen Python Code und Repräsentation für den Webseitenbesucher zu erreichen, gibt es ein eigenes Django-Template System. base.html
<html>  
  <head><title>{% block title %}{% endblock %}</title></head>
  <body>
    {% block content %}
    {% endblock %}
  </body>
</html>

start/start.html

{% extends "../base.html" %}
{% block title %}Hello - World{% endblock %}
{% block content %}
  {{ text }}
{% endblock %}

Die beiden Dateien zeigen die wichtigsten Elemente des Django Template Systems. Die Datei base.html definiert dabei die grobe Struktur. Hier wird das Basis-Layout festgelegt, welches dann von den anderen Template Dateien eingebunden wird. Diese erben allen Inhalt aus base.html und überschreiben dann die benötigten Blöcke.

Wir erstellen außerdem aus Gründen der Übersichtlichkeit, für jede Anwendung ein Unterverzeichnis indem die Templates für eben diese Anwendung liegen.

Der zu dem oben stehenden Template passende View könnte z.B. so aussehen:

from django.http import HttpResponse
from django.template import Context
from django.template.loader import get_template
import datetime

def hello_world(req):
  text = "Hello World it is %s" % datetime.datetime.now()
  t = get_template('start/start.html')
  html = t.render(Context({'text': text}))
  return HttpResponse(html)

Und weil man diese Funktionalität in so vielen views braucht, bietet Django für die Aufgabe "Context erzeugen -> Template rendern -> HttpResponse? zurückgeben" einen Shortcut.

from django.shortcuts import render_to_response
import datetime

def hello_world(req):
  text = "Hello World it is %s" % datetime.datetime.now()
  return render_to_response('start/start.html', {'text': text})

Model

Models sind eine Abstraktion der Datenbank. Im Prinzip definiert man hier das Datenbankdesign. Allerdings nicht in SQL sondern mit Python. Der Vorteil erschließt sich erst, wenn man einmal eine Webapplikation auf unterschiedlichen Datenbanksystemen installieren wollte. Django kümmert sich um die Umsetzung der in der models.py angegebenen Informationen auf die konfigurierte Datenbank.

Ein Django-Model sieht z.B. so aus:

models.py

from django.db import models

class Publisher(models.Model):
  name = models.CharField(max_length=30)
  website = models.URLField()

class Author(models.Model):
  name = models.CharField(max_length=30)
  email = models.EmailField()
  
class Book(models.Model):
  title = models.CharField(max_length=100)
  authors = models.ManyToManyField(Author)
  publisher = models.ForeignKey('Publisher')
  date = models.DateField()

Verwendet man eine sqlite Datenbank erstellt Django aus dem oben stehen Model den folgenden SQL-Code.

BEGIN;
CREATE TABLE "start_publisher" (
    "id" integer NOT NULL PRIMARY KEY,
    "name" varchar(30) NOT NULL,
    "website" varchar(200) NOT NULL
)
;
CREATE TABLE "start_author" (
    "id" integer NOT NULL PRIMARY KEY,
    "name" varchar(30) NOT NULL,
    "email" varchar(75) NOT NULL
)
;
CREATE TABLE "start_book_authors" (
    "id" integer NOT NULL PRIMARY KEY,
    "book_id" integer NOT NULL,
    "author_id" integer NOT NULL REFERENCES "start_author" ("id"),
    UNIQUE ("book_id", "author_id")
)
;
CREATE TABLE "start_book" (
    "id" integer NOT NULL PRIMARY KEY,
    "title" varchar(100) NOT NULL,
    "publisher_id" integer NOT NULL REFERENCES "start_publisher" ("id"),
    "date" date NOT NULL
)
;
CREATE INDEX "start_book_22dd9c39" ON "start_book" ("publisher_id");
COMMIT;

Ausgeben lassen kann man sich den Code mit:

python manage.py sqlall start

Wichtige Einstellungen in der settings.py

Die Zentrale Steuerdatei settings.py von Django liegt im Projektverzeichnis und ist gut dokumentiert. Das einzige was wir zum ausprobieren ändern sollten sind die folgenden Einstellungen.

Die Zeitzone steht nach dem erzeugen des Projektes auf 'America/Chicago'

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = None

Außerdem müssen wir unsere Anwendung den _INSTALLED_APPS_ hinzufügen.
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'start',
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
)