Wprowadzenie do Django 1.0 - Tworzymy prostego bloga

Opis tworzenia prostej strony w Django 1.0 z wykorzystaniem modeli, widoków, szablonów i panelu admina.

Niniejszy artykuł przedstawia ścieżkę tworzenia prostej aplikacji w Django 1.0. Jeżeli znasz poprzednie jego wersje ten artykuł pomoże ci w migracji do nowej wersji zawierającej kilka wstecznie niezgodnych zmian. Jeżeli nie znasz jeszcze frameworka - ten artykuł przedstawi ci jego budowę i możliwości.

Tworzenie i konfiguracja projektu i aplikacji

Projekt, czyli katalog z wszystkimi plikami serwisu tworzymy wykonując polecenie django-admin.py startproject NAZWA_PROJEKTU. Aplikacje, czyli poszczególne składowe projektu (wiadomości, komentarze, forum itd.) tworzymy wykonując w katalogu projektu polecenie python manage.py startapp NAZWA_APLIKACJI. W artykule stworzymy projekt "blog" i aplikację "news":
django-admin.py startproject blog
cd blog
python manage.py startapp news
Kolejny etap to konfiguracja bazy danych i innych ustawień w pliku settings.py. W tym artykule skorzystam z bazy SQLite konfigurując ją tak:
DATABASE_ENGINE = 'sqlite3'           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = 'baza'             # Or path to database file if using sqlite3.
Dodatkowo zmieniam język na polski - LANGUAGE_CODE = 'pl'. Inne ważne sekcje tego pliku, które będziemy modyfikować to: Teraz możemy stworzyć bazę danych i podstawowe tabele poleceniem:
python manage.py syncdb
W czasie wykonywania którego zostaniemy poproszeni o stworzenie konta superużytkownika podając login, email i hasło. By uruchomić serwer deweloperski służący do testowania projektu wystarczy wydać polecenie:
python manage.py runserver
Strona będzie dostępna pod adresem http://localhost:8000/

Panel Admina

Django posiada rozbudowany i generowany "automatycznie" Panel Admina dla naszych aplikacji. By go uruchomić upewnij się czy masz 'django.contrib.admin', dodane do INSTALLED_APPS (jeżeli nie to dodaj i wykonaj polecenie "syncdb"). Następnie edytuj plik urls.py do postaci:
from django.conf.urls.defaults import *

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
   (r'^admin/(.*)', admin.site.root),
)
Pod adresem http://localhost:8000/admin/ dostępny będzie Panel Admina, do którego logujemy się danymi podanymi przy tworzeniu bazy danych / superużytkownika. Po zalogowaniu zobaczymy coś takiego:
newdjango1.png
Możemy zarządzać kontami użytkowników, czy też tworzyć grupy posiadające różne uprawnienia. "Strony" to aplikacja, która przydaje się gdy chcemy uruchomić więcej niż jeden serwis bazujący na tym samym kodzie i bazie danych (na razie omijamy tą aplikację). Stworzone przez nas aplikacje będą posiadały w Panelu Admina interfejs pozwalający na zarządzanie rekordami (dodaj, edytuj, usuń itp.).

Modele

Każda tabela tworzona przez Django opisana jest modelem - klasą zawierającą definicje poszczególnych kolumn. Modele znajdują się w plikach models.py poszczególnych aplikacji. W naszym przypadku - news/models.py. Oto gotowe modele dla kategorii wiadomości i samych wiadomości:
# -*- coding: utf-8 -*-
from django.db import models

class Category(models.Model):
	name = models.CharField(max_length=255, verbose_name='Nazwa Kategorii')
	slug = models.SlugField(max_length=255, unique=True, verbose_name='Odnośnik')
	icon =  models.ImageField(upload_to='icons', verbose_name='Ikonka Kategorii', blank=True)
	class Meta:
		verbose_name = "Kategoria"
		verbose_name_plural = "Kategorie"
	def __str__(self):
		return self.name
	def __unicode__(self):
		return self.name

class News(models.Model):
	category = models.ManyToManyField(Category, verbose_name='Kategorie')
	title = models.CharField(max_length=255, verbose_name='Tytuł')
	slug = models.SlugField(max_length=255, unique=True, verbose_name='Odnośnik')
	text = models.TextField(verbose_name='Treść')
	date = models.DateTimeField(verbose_name='Data dodania')
	wykop = models.CharField(max_length=255, verbose_name='Wykop', blank=True)
	class Meta:
		verbose_name = "Wiadomość"
		verbose_name_plural = "Wiadomości"
	def __str__(self):
		return self.title
	def __unicode__(self):
		return self.title
	def get_absolute_url(self):
		return '/news/' + self.slug + '/'
Mamy model "Category" dla listy kategorii - posiadających nazwę ("name"), odnośnik ("slug", nazwa pozbawiona znaków niedopuszczanych w URLach), oraz "pole" na ikonę kategorii - "icon". Jak widać każe z tych pól ma określony typ - models.CharField - pole tekstowe (VARCHAR), models.SlugField - pole tekstowe z walidacją znaków niedopuszczanych w odnośnikach, czy też np. models.TextField - pole tekstowe (TEXT). Pole ManyToManyField to pole relacji pozwalające przypisywać wiele kategorii do danej wiadomości. Opis wszystkich pól i argumentów jakie przyjmują dostępny jest w oddzielnym artykule. Gdy mamy gotowy model możemy stworzyć tabele. Wystarczy ponownie wykonać:
python manage.py syncdb

Panel Admina dla modeli

Dla Django 1.0 konfiguracja Panelu Admina dla modeli odbywa się poprzez plik admin.py umieszczony w katalogu aplikacji (news/admin.py). Oto najprostszy przypadek udostępniania modeli w PA:
# -*- coding: utf-8 -*-
from django.contrib import admin

#import pliku z modelami
from news.models import *

#rejestrujemy każdy model podając jego nazwę
admin.site.register(Category)
admin.site.register(News)
Po restarcie serwera deweloperskiego w Panelu Admina powinniśmy zobaczyć nasze modele:
newdjango2.png
Możemy teraz dowolnie zarządzać danymi w tych modelach.
newdjango3.png
Panel Admina posiada bardzo szerokie możliwości dopasowywania. Za pomocą klasy NAZWA_MODELUAdmin możemy wpływać na wygląd formularzy dodawania/edycji, dane wyświetlane na liście istniejących wpisów i znacznie więcej. Oto przykład:
# -*- coding: utf-8 -*-
from django.contrib import admin

from news.models import *

# dla kategorii
class CategoryAdmin(admin.ModelAdmin):
	list_display = ('name','icon')
	prepopulated_fields = {'slug': ('name',)}

# dla wiadomości
class NewsAdmin(admin.ModelAdmin):
	list_display = ('title','date')
	prepopulated_fields = {'slug': ('title',)}

# rejestracja wraz z podaniem klasy konfigurującej PA
admin.site.register(Category, CategoryAdmin)
admin.site.register(News, NewsAdmin)
Zastosowaliśmy tutaj list_display - listę pól, jakie mają byś wyświetlane na liście wpisów, oraz prepopulated_fields - słownik określający pola, z których mają być generowane wartości dla pól odnośnikowych "Slug". Dodając nazwę kategorii ("name") automatycznie wstawiony zostanie przefiltrowany tekst do pola odnośnika "slug". Podobnie dla wiadomości.
newdjango4.png
W tej chwili mamy gotowy Panel Admina zarządzający naszym "blogiem". Brakuje nam części wyświetlającej wiadomości dla odwiedzających stronę.

Widoki

Django stosuje wzorzec projektowy Model-Szablon-Widok, gdzie logika bazodanowa jest w modelu, szablon określa wygląd (HTML), a widok spina to razem zwracając gotowy wynik (gotową stronę). Widoki definiowane są w pliku views.py aplikacji (news/views.py). Oto prosty widok:
# -*- coding: utf-8 -*-
from django.template import RequestContext
from django.shortcuts import render_to_response

from news.models import *

def index(request):
	return render_to_response('index.html',
			{'zmienna': 'Jestem widokiem'},
			context_instance=RequestContext(request))
Każdy widok to funkcja przyjmująca co najmniej jeden argument - "request" (dane żądania, POST, GET, SESSION itd.) i musi zwrócić odpowiedź - zazwyczaj będziemy stosować funkcję "render_to_response" zwracającą gotowy wynik z wykorzystaniem szablonu. W tym przykładzie używamy szablonu index.html (umieszczonego w katalogu templates) o kodzie:
<h1>Moja Strona </h1>
{{ zmienna }}
render_to_response przyjmuje kilka argumentów - nazwę szablonu, słownik ze zmiennymi przekazywanymi do szablonu, oraz "RequestContext", co obecnie możemy pominąć (udostępnianie zmiennych globalnych dla wszystkich szablonów). Opis widoków oraz obiektu request znajdziemy w oddzielnym artykule.

Odnośniki

W Django odnośniki, pod którymi są dostępne określone widoki są mapowane za pomocą reguł z wyrażeniami regularnymi w plikach urls.py. W naszym pliku urls.py mamy już podaną regułę dla panelu admina, teraz musimy podać regułę dla naszego widoku index:
from django.conf.urls.defaults import *

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
   (r'^admin/(.*)', admin.site.root),
   (r'^/?$', 'news.views.index'),
)
Reguła mapująca ma postać:
(r'REGUŁA', 'WIDOK'),
Gdzie do widoku odwołujemy się poprzez nazwa_aplikacji.views.nazwa_widoku. Opis mapowania odnośników znajdziemy w oddzielnym artykule. Po zapisaniu zmian pod adresem http://localhost:8000/ powinniśmy zobaczyć nasz widok:
newdjango5.png

Operowanie na danych, ORM

Mając modele możemy operować na nich (pobierać, dodawać, czy edytować dane) poprzez ORM Django. Standardowo dostęp do modelu uzyskujemy poprzez:
NAZWA_MODELU.objects.METODA_OPERACJI()
Przykładowo pobranie kategorii o ID 1 wyglądałoby tak:
Category.objects.get(id=1)
A wszystkich wiadomości tak:
News.objects.all()
Opis wszystkich możliwości ORMa znajduje się w oddzielnym artykule. Zmodyfikujmy teraz nasz widok do postaci:
def index(request):
	news = News.objects.all().order_by('-id')
	return render_to_response('index.html',
			{'news': news},
			context_instance=RequestContext(request))
Jak widać pobieramy wszystkie wiadomości, sortujemy je malejąco po ID i wynik przekazujemy do szablonu:
<h1>Moja Strona </h1>
{% for n in news %}
	<h3>{{ n.title }}</h3>
	{{ n.text|safe }}<br />
	{{ n.date|date:"Y.m.d H:i" }}
{% endfor  %}
newdjango6.png
W efekcie na stronie głównej pojawi się lista wiadomości. Jak widać szablony Django posiadają szereg filtrów i tagów, z których dość często będziemy korzystać. Pętla "for" pozwala wyświetlić po kolei dane z listy. Filtry stosowane na zmiennych {{ zmienna|filtr|filtr2 }} mogą określać ich formatowanie (filtr |date określający wyświetlany format czasu), czy też np |safe zezwalać na stosowanie tagów HTML w przesłanej zmiennej. Szablony obsługują także dziedziczenie - możliwość definiowana bloków w szablonie głównym i dziedziczenia go przez inne szablony, które wypełniają danymi istniejące bloki i zwracające kompletną stronę. Opis szablonów znajdziemy w oddzielnym artykule. O tym i innych możliwościach Django w następnej części (lub też możesz odkrywać je samemu czytając dokumentacje i istniejące artykuły i przykłady).