Wstęp do Django 1.0 - artykuł
Artykuł opisuje Django jako narzędzie do tworzenia prostych i zaawansowanych aplikacji webowych. Django cechuje szybkość i łatwość tworzenia aplikacji oraz czysta i pragmatyczna architektura. Artykuł przedstawia historię powstawania frameworku, jego główne funkcjonalności jak również architekturę. W części praktycznej zostanie opisany proces tworzenia prostej aplikacji webowej przy użyciu Django. Udowodnimy w ten sposób, że pisząc niecałe 100 linii kodu jesteśmy w stanie stworzyć kompletną aplikację webową.
Poniższy artykuł został opublikowany w książce "PyCon PL 2008", która została wydana w październiku 2008
Wstęp
Django jest frameworkiem wysokiego poziomu, napisanym w języku Python, który pomaga tworzyć proste i zaawansowane aplikacje webowe. Cechuje go szybkość i łatwość tworzenia aplikacji, oraz czysta i pragmatyczna architektura, oparta na regule DRY (ang. "Don't Repeat Yourself").
Historia
Zanim zagłębimy się w szczegóły techniczne i architekturę, warto zatrzymać się na chwilę, aby dowiedzieć się skąd się wzięło Django i co wpłynęło na jego obecny kształt. Historia Django sięga roku 2003, kiedy grupa programistów (Adrian Holovaty, Simon Willison i Jacob Kaplan-Moss) związana z gazetą Lawrence Journal-World w Kansas zaczęła tworzyć wersję internetową tejże gazety. Przez dwa lata programiści pisali na własne potrzeby biblioteki i narzędzia, z których ostatecznie wyodrębnił się samodzielny framework. W roku 2005 postanowiono otworzyć kod źródłowy frameworku i udostępnić go na licencji BSD pod nazwą Django. Nazwa frameworku została nadana od imienia cygańskiego gitarzysty Django Reinhardta, który jest jednym z ulubionych wykonawców Adriana Holovaty. Od tamtego czasu Django bardzo się rozpowszechniło, zdobyło dużą popularność i jest powszechnie używane do tworzenia stron i aplikacji webowych. Jego walory wykorzystywane są zarówno w prostych blogach, jak również w zaawansowanych serwisach Web 2.0 (przykładem jest polski serwis społecznościowy Grono.net).
Aktualnie dostępna wersja Django to 1.0.2.
Główne funkcje
Django jest kompletną i samodzielną platformą do tworzenia aplikacji webowych. Jego podstawowymi elementami są: serwer HTTP, interaktywna konsola (działająca bezpośrednio w środowisku aplikacji), skrypty (automatyzujące takie czynności jak tworzenie bazy danych, importowanie i eksportowanie danych) oraz duży zbiór funkcji i bibliotek.
W skład samego frameworku wchodzą:
- mechanizm mapowania obiektowo-relacyjnego (ang. ORM - object-relational mapping), który odwzorowuje obiekty na strukturę bazy danych,
- automatyczny interfejs administracyjny - moduł do zarządzania danymi przechowywanymi w bazie danych (przeglądanie, dodawanie, usuwanie i edycja),
- zarządzania adresami URL – przyjazny i oparty na wyrażeniach regularnych mechanizm do mapowania adresów URL do konkretnych widoków URL,
- system szablonów – prosty i jednocześnie funkcjonalny język dla grafików i programistów do generowania plików (HTML, XML, CSV, itp),
- formularze – mechanizm do tworzenia i przetwarzania HTML-owych formularzy,
- uwierzytelnianie i autoryzacja – mechanizm logowania do systemu i zarządzanie dostępem do zasobów (stron lub danych),
- cache – buforowany dostęp do danych,
- lokalizacja - wsparcie dla wielojęzycznych aplikacji.
Architektura
W procesie tworzenia architektury Django jego autorzy korzystali z koncepcji wzorca projektowego MVC (ang. Model-View-Controller). Idea ta determinuje podział frameworku na trzy niezależne warstwy: model danych, widok i logikę. Tym samy także w Django możemy wyodrębnić trzy niezależne warstwy. Jednakże autorzy frameworku pozwolili sobie na małą modyfikację tworząc własny wzorzec Model-View-Template. W modelu tym każdej z warstw przypisujemy integralny zakres odpowiedzialności:
- model - odpowiedzialny jest za zarządzanie danymi (dodawanie, czytanie,
usuwanie i modyfikowanie), które są przechowywane w bazie danych.
- widok - odpowiedzialny za wyciągnięcie odpowiednich danych,
przetworzenie ich i przekazanie do użytkownika (za pośrednictwem szablonów).
szablon - odpowiedzialny za prezentację wyników widoków.
Pomiędzy poszczególnymi warstwami następuje nieustanny obieg informacji. Proces ten opisać można w kilku krokach:
- Przeglądarka pyta serwer o konkretny adres URL.
- Django przetwarza plik urls.py w poszukiwaniu wzorca pasującego do adresu URL.
- Kiedy wzorzec zostanie dopasowany, Django przekazuje zapytanie do odpowiadającego widoku.
- Widok przetwarza dane z bazy danych i wygenerowany wynik przekazuje do szablonu.
- Szablon wyświetla dane dostarczone przez widok.
Graficzna prezentacja tego procesu zilustrowana jest poniżej:
Instalacja
Przystępując do instalacji Django należy zwrócić uwagę na fakt, że Django jest dystrybuowane w kilku różnych wersjach. Zatem jego instalacji można wykonać z gotowych pakietów dla określonej dystrybucji, albo ściągając gotową paczkę z oficjalnej strony lub bezpośrednio z repozytorium wersję rozwojową. W zależności od wybranej wersji, proces instalacji frameworku będzie różnił się nieznacznie. Więcej szczegółów na ten temat można znaleźć na oficjalnej stronie projektu. Poniżej znajduje się przykład, w jaki sposób zainstalować Django bezpośrednio z repozytorium Subversion.
W celu pobrania Django na lokalny dysk wykonujemy następujące polecenie:
~$ svn co http://code.djangoproject.com/svn/django/trunk/ django
Następnie za pomocą polecenia setup.py install instalujemy Django w katalogu Pythona site-packages.
~$ cd django
~/django$ sudo python setup.py install
Ostatnim krokiem jest pobranie odpowiedniego sterownika bazy danych. Dla każdego rodzaju bazy należy zainstalować odpowiedni pakiet:
Pierwsza aplikacja
Aby przybliżyć faktyczne możliwości Django, stworzymy przykładową aplikację. Będzie to prosty blog składający się z dwóch modułów:
- moduł publiczny, którego zadaniem jest wyświetlanie listy
wpisów oraz szczegółów o danym wpisie,
- moduł administracyjny, który jest dostępny wyłącznie dla
zalogowanych użytkowników i jest odpowiedzialny za zarządzania wpisami (dodawanie, edycja i usuwanie).
Let's get ready to rumble!
Na początku stworzymy podstawową strukturę naszego projektu z domyślnymi plikami. W tym celu wykorzystamy skrypt django-admin.py, który jest dostarczony razem z Django i znajduje się w katalogu bin.
Wykonujemy następujące polecenie:
~$ django-admin.py startproject webapp
Skrypt tworzy katalog webapp służący do przechowywać kodu źródłowego aplikacji. Ponadto wygenerowane są cztery pliki:
~$ ls -1 webapp/
__init__.py
manage.py
settings.py
urls.py
Już na tym etapie możemy uruchomić aplikację. Aby tego dokonać wykonujemy polecenie manage.py runserver w następujący sposób:
~$ cd webapp
~/webapp$ python manage.py runserver
Validating models...
0 errors found
Django version 1.0.2 final, using settings 'webapp.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[29/Jul/2008 10:02:36] "GET / HTTP/1.1" 200 2049
Moduł Administracyjny
Kolejnym krokiem jaki wykonamy jest konfiguracja modułu administracyjnego. Stworzenie tego modułu jest niezbędne w celu zarządzania użytkownikami oraz zawartością bloga. Aby stworzyć moduł administracyjny wystarczy:
- skonfigurować bazę danych (parametry DATABASE_ENGINE
i DATABASE_NAME w pliku settings.py),
- dodać panel administracyjny (należy dodać jedną linię w pliku
settings.py i odkomentować trzy linie w pliku url.py.
settings.py:
# Silnik bazy danych
DATABASE_ENGINE = 'sqlite3'
# Nazwa bazy danych (dla SQLite jest to ścieżka do pliku bazy)
DATABASE_NAME = 'database.db'
# Ustawienia domyślnego języka dla aplikacji
LANGUAGE_CODE = 'pl'
# Lista modułów
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
)
urls.py:
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^webapp/', include('webapp.foo.urls')),
# Uncomment the next line to enable admin documentation:
#(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line for to enable the admin:
(r'^admin/(.*)', admin.site.root),
)
Następnie tworzymy strukturę bazy danych ponownie korzystając z pomocy skryptu manage.py. W tym procesie tworzymy także pierwszego użytkownika z prawami administratora. Skrypt zapyta nas o parametry konta administratora, czyli nazwę użytkownika, hasło oraz adres email.
~/webapp$ python manage.py syncdb
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
Creating table django_admin_log
You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username: root
E-mail address: root@root.com
Password:******
Password (again): ******
Superuser created successfully.
Installing index for auth.Permission model
Installing index for auth.Message model
Installing index for admin.LogEntry model
Możemy teraz uruchomić naszą aplikację. Aby podglądnąć efekt dotychczasowej pracy uruchamiamy manage.py runserver i pod adresem http://127.0.0.1:8000/admin/ pojawi się panel administracyjny. Już na tym etapie dostępne są dla nas funkcje zarządzania użytkownikami.
Moduł publiczny
Pierwszą część (moduł administracyjny) mamy już za sobą. Teraz możemy przystąpić do napisania kodu właściwego, który będzie odpowiedzialny za wyświetlanie wpisów i ich szczegółów na stronie bloga. Złożą się na to trzy podstawowe etapy:
stworzenie modelu,
- stworzenie widoku, który pozwala na wydobycie odpowiednich
danych z modelu,
- stworzenie szablonu do wyświetlenia danych, zaprojektowanie
adresów URL dla poszczególnych stron.
Zaczynamy od stworzenia modułu i w tym celu ponownie skorzystamy ze skryptu manage.py:
~webapp$ python manage.py startapp blog
~webapp$ ls -1 blog/
__init__.py
models.py
views.py
Skrypt utworzył katalog blog a w nim trzy puste pliki: __init__.py, models.py (model danych) i views.py (widok). Należy teraz zaprojektować model danych (plik models.py). Model ten będzie zawierał tytuł ("title"), unikalna etykieta ("slug"), treść ("body") i datę publikacji ("pub_date"). Przykład zawartości pliku blog/models.py znajduje się poniżej:
from django.db import models
from django.contrib import admin
class Entry(models.Model):
""" Model danych reprezentujący wpis """
# Tytuł wpisu
title = models.CharField('Tytul', max_length=200)
# Unikalna (dla daty) etykieta wpisu
slug = models.SlugField(unique_for_date='pub_date')
# Treść wpisu
body = models.TextField('Tresc')
# Data publikacji
pub_date = models.DateField('Data publikacji')
# Nazwa pod jaką będzie wyświetlany wpis w panelu administracyjnym
def __unicode__(self):
return u'%s' % (self.title)
# URL wpisu (np. /2008/08/03/pycon-pl/)
def get_absolute_url(self):
return "/%s/%s/" % (self.pub_date.strftime("%Y/%m/%d"),
self.slug)
class Meta:
""" Metadane – opis i konfiguracja modelu """
# Nazwa obiektu czytelna dla człowieka
verbose_name = 'Wpis'
# Nazwa obiektu czytelna dla człowieka w liczbie mnogiej
verbose_name_plural = 'Wpisy'
class EntryAdmin(admin.ModelAdmin):
""" Model danych aby był widoczny w panelu administracyjnym musi mieć
zarejestrowaną klasę ModelAdmin """
# Automatyczne generowanie pola 'slug' na podstawie pola 'title'
prepopulated_fields = {'slug': ('title',)}
# Rejestracja klasy EntryAdmin aby była widoczna w panelu administracyjnym
admin.site.register(Entry, EntryAdmin)
Teraz rejestrujemy panel publiczny poprzez dodanie modułu blog do pliku settings.py (parametr INSTALLED_APPS). Jest to operacja analogiczna do tej jaką wykonaliśmy przy dodawaniu panelu administracyjnego (django.contrib.admin).
settings.py:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'blog',
)
W kolejnym etapie skupimy się na tworzeniu widoku (plik views.py), który będzie bezpośrednio korzystał z modelu danych (plik models.py). W przykładzie tworzonego bloga w widoku wyróżnimy trzy funkcje:
- strona główna (latest) – wyświetlanie najnowszy wpisów,
- archiwum (archive) – archiwum wpisów (lata, miesiące i dni),
- szczegóły (detail) – wyświetlanie szczegółów wpisu.
Zawartość pliku blog/views.py znajduje się poniżej:
from webapp.blog.models import Entry
from django.shortcuts import render_to_response, get_object_or_404
from django.db.models import Q
import datetime
def latest(request):
""" Lista ostatnich wpisów """
# Pobranie z bazy danych ostatnich pięciu wpisów
entries = Entry.objects.all().order_by('-pub_date')[:5]
# Przekazanie list wpisów (entries) do szablonu list.html
return render_to_response('list.html', {'entries': entries })
def archive(request, year, month = 0, day = 0):
""" Archiwum wpisów """
# Tworzenie zapytania do bazy danych, które pobierze wpisy opublikowane
# w podanym roku – parametr year
query = Q(pub_date__year = int(year))
# Dodanie zapytania o konkretny miesiąc
if month != 0:
query &= Q(pub_date__month = int(month))
# Dodanie zapytania o konkretny dzień
if day != 0:
query &= Q(pub_date__day = int(day))
# Pobranie z bazy danych wpisów pasujących do zapytania
entries = Entry.objects.filter(query)
# Przekazanie list wpisów (entries) do szablonu list.html
return render_to_response('list.html', {'entries': entries })
def detail(request, year, month, day, slug):
""" Wyświetlanie szczegółów wpisu """
date = datetime.date(int(year), int(month), int(day))
# Pobranie z bazy danych wpisu pasującego do podanej daty i sluga
entry = get_object_or_404(Entry, pub_date = date, slug = slug)
# Przekazanie pojedynczego wpisu (entry) do szablonu detail.html
return render_to_response('detail.html', {'entry': entry })
Pozostało nam już tylko zaprojektowanie interfejsu użytkownika. Aby tego dokonać tworzymy szablony, które generują strony HTML. Dla potrzeb bloga w katalogu template tworzymy dwa szablony: listę oraz szczegóły wpisów. Każdy z tych szablonów jest odrębnym plikiem:
- listę wpisów bloga zapisujemy w pliku template/list.html.
Zawiera on: tytuł, data publikacji, skrót treści (pierwsze 20 wyrazów) a także link do szczegółów.
- szczegóły wpisu znajdują się w pliku template/detail.html.
Zawiera on: tytuł, data publikacji oraz pełną treść wpisu.
Przykład zawartości pliku template/list.html:
{% for entry in entries %}
<h2>{{ entry.title }}</h2>
<p>{{ entry.pub_date|date:"d F Y" }}</p>
{{ entry.body|truncatewords_html:"20"|safe }}
<p><a href="{{entry.get_absolute_url}}">czytaj więcej...</a></p>
{% endfor %}
Przykład zawartości pliku template/detail.html:
<h1>{{ entry.title }}</h1>
<p>{{ entry.pub_date|date:"d F Y" }}</p>
{{ entry.body|safe }}
Następnie w pliku settings.py odszukujemy zmienną TEMPLATE_DIRS i dodajemy do niej katalog template. W ten sposób wskazujemy Django gdzie ma szukać stworzonych wcześniej szablonów list.html i detail.html.
settings.py:
TEMPLATE_DIRS = (
'template',
)
Jedną z unikalnych funkcji Django jest możliwość projektowania adresów URL. Do tego celu Django udostępnia nam gotowe narzędzie (plik urls.py), które do mapowania adresów URL na konkretne widoki wykorzystuje wyrażenia regularne. Na przykład adresowi /2008/08/12/ będzie odpowiadała funkcja detail w pliku views.py.
Na potrzeby bloga stworzyliśmy plik blog/urls.py zawierający mapowanie adresów URL na widoki. Przykład znajduje się poniżej:
from django.conf.urls.defaults import *
urlpatterns = patterns('webapp.blog.views',
# Szczegóły (np. /2008/08/03/pycon-pl/)
(r'(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/(?P<slug>[-\w]+)/$', 'detail'),
# Archiwum dla konkretnej daty (np. /2008/08/03/)
(r'(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', 'archive'),
# Archiwum dla konkretnego roku i miesiąca (np. /2008/08/)
(r'(?P<year>\d{4})/(?P<month>\d{2})/$', 'archive'),
# Archiwum dla konkretnego roku (np. /2008/)
(r'(?P<year>\d{4})/$', 'archive'),
# Głowna strona (/)
(r'^$', 'latest'),
)
Aby zakończyć proces tworzenia blogu niezbędna jest jeszcze jedna mała modyfikacja. Do głównego pliku urls.py dodajemy referencje do wcześniej stworzonych adresów URL (plik blog/urls.py).
urls.py:
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Uncomment the next line to enable admin documentation:
#(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line for to enable the admin:
(r'^admin/(.*)', admin.site.root),
# Referencja do pliku blog/urls.py
(r'^', include('webapp.blog.urls')),
)
Na koniec uaktualniamy strukturę bazy danych o świeżo stworzony model Entry. W tym celu uruchamiamy skrypt manage.py syncdb, który na podstawie zdefiniowanego modelu utworzy niezbędne tabele w bazie danych.
~/webapp$ python manage.py syncdb
Creating table blog_entry
Installing index for blog.Entry model
Teraz pozostaje nam już tylko uruchomić aplikację wykonując polecenie manage.py runserver.
~/webapp$ python manage.py runserver
Validating models...
0 errors found
Django version 1.0-alpha-SVN-unknown, using settings 'webapp.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[29/Jul/2008 10:02:36] "GET / HTTP/1.1" 200 2049
Po wprowadzeniu adresu http://127.0.0.1:8000/ w przeglądarce internetowej dostępna jest nasza nowo napisana aplikacja. A pod adresem http://127.0.0.1:8000/admin/ mamy dostęp do Panelu Administracyjnego, gdzie możemy wprowadzać nowe dane.
Panel Administracyjny - głowne okno
Panel Administracyjny - wprowadzanie danych
Głowna strona - lista wspisów
Szczegóły wspisu
Podsumowanie
Przedstawiony pokrótce proces tworzenia aplikacji z wykorzystaniem frameworku Django pokazuje jedynie mały fragment możliwości jakie oferuje to narzędzie. Artykuł udowadnia, że pisząc niecałe 100 linii kodu jesteśmy w stanie stworzyć kompletną aplikację webową. To powoduje, że z roku na rok Django zyskuje kolejnych zwolenników wśród firm i indywidualnych programistów systemów internetowych.
Warto zobaczyć
Aby dobrze poznać Django i wszystkie oferowane przez niego funkcje, warto korzystać z dokumentacji i przykładów gotowych aplikacji i bibliotek. Poniżej przedstawiam listę stron, które warto regularnie odwiedzać:
- http://www.djangoproject.com/ - główna strona projektu Django,
- http://www.djangobook.com/ - wersja elektroniczna książki o Django,
- http://www.django.pl/ - polska strona projektu
- http://www.djangosites.org/ - lista stron stworzonych w Django,
- http://djangogigs.com/ - oferty pracy dla programistów Django,
- http://www.djangosnippets.org/ - przykłady i fragmenty kodów źródłowych,
- http://djangopeople.net/ - programiści Django wszystkich krajów – łączcie się!
Marcin Mierzejewski, 18 październik 2008