Wprowadzenie do Django - Tworzymy prostego bloga

Opis tworzenia prostej strony w Django 1.X Poznajemy budowę frameworka i proces tworzenia aplikacji z wykorzystaniem modeli, widoków, szablonów i panelu admina Django

Ten artykuł prezentuje sposób tworzenia aplikacji z wykorzystaniem Django. Jeżeli chcesz poznać ten framework to uważnie zapoznaj się z tym artykułem. Opanowując zaprezentowane tutaj podstawy będziesz mógł szybko i przyjemnie poznać kolejne elementy Django jak i zacząć tworzyć prawdziwe aplikacje www.

Zanim rzucisz się w wir tworzenia stron w Django zapoznaj się z jego kluczowymi komponentami. Wielu młodych programistów zbyt szybko zaczyna pisać aplikacje w Django i natrafia na problemy "jak coś zrobić", co kończy się tworzeniem "haków" i brzydkiego kodu. Django naprawdę wiele potrafi, trzeba tylko na spokojnie podejść do jego nauki :)

Instalacja Django

Zakładam że masz już Pythona zainstalowanego na komputerze i znasz jego podstawy. Django można zainstalować na dwa sposoby. Pierwszy poprzez PIP wykonując w konsoli polecenie:

pip install django

Django można także zainstalować ręcznie pobierając pakiet ze strony djangoproject. Rozpakowujemy go a następnie w konsoli przechodzimy do katalogu z rozpakowanym Django i wykonujemy polecenie:

python setup.py install

W przypadku Linuksa by zainstalować Django w systemie trzeba te polecenia wykonać z konta roota lub stosując "sudo" w dystrybucjach takich jak Ubuntu (dystrybucjach używających sudo). Dość często django jest w postaci pakietu w repozytorium - ale może być w nieco starszej wersji.

Co będzie nam jeszcze potrzebne?

Dla pełnej przyjemności przyda się nam edytor kodu, IDE obsługujące kod Pythona jak i szablony HTML, CSS, JS - wszystko co potrzebne jest do pisania kodu stron internetowych. Z aplikacji można wymienić Komodo Edit, Sublime Text 2, PyCharm, czy PyDev.

Django wykorzystuje bazy danych. Na potrzeby tego artykułu wykorzystam najprostszą - SQLite, dla której nie trzeba nic więcej instalować. W przypadku baz MySQL musimy zainstalować pakiet "mysql-python", a w przypadku baz PostgreSQL - "psycopg2" (instalujemy poprzez PIP). Dodatkowo do części frameworka powiązanych z grafikami/zdjęciami potrzebować będziemy pakietu "pil".

Tworzymy pierwszą stronę opartą o Django

Tworzenie projektu i aplikacji Django

Każdy serwis, strona internetowa stworzona za pomocą Django to projekt - katalog zawierający cały kod strony. W skład tego kodu wchodzą aplikacje - np. newsy, forum, artykuły to przykłady trzech możliwych aplikacji Django.

Zaczynamy od stworzenia projektu. W konsoli wykonujemy polecenie:

django-admin.py startproject NAZWA_PROJEKTU

Polecenie to stworzy katalog projektu o podanej nazwie oraz stworzy w nim podstawowe pliki. Po wejściu do tego katalogu możemy tworzyć aplikacje za pomocą polecenia startapp. Ja stworzę teraz projekt "blog" i aplikację "news":

django-admin.py startproject blog
cd blog
python manage.py startapp news

Struktura projektu i aplikacji

W tej chwili w katalogu projektu "blog" mamy następującą strukturę plików i katalogów:
blog
  - __init__.py
  - settings.py
  - urls.py
  - wsgi.py
news
  - __init__.py
  - models.py
  - tests.py 
  - views.py
manage.py

Mamy więc podkatalog blog - nazwany tak samo jak projekt. Katalog ten przechowuje konfigurację projektu. settings.py przechowuje wszystkie ustawienia i to jego będziemy często odwiedzać. urls.py to drugi ważny plik - tutaj przypisujemy widok do podanego adresu URL. Dla programistów np PHP może to być spora nowość. Nie wywołujemy plików poprzez adresy URL, tylko przypisujemy widok/stronę jaka ma być wyświetlona dla podanego adresu URL (np. /news/ czy /forum/topic/1/ a nie news.php, czy forum.php?topic=1). Przy okazji od razu dostajemy "ładne" adresy URL.

Katalog news to katalog aplikacji. Każda aplikacja zaczyna z trzema istotnymi plikami:

  • models.py: plik modeli aplikacji (każdy model opisuje tabelę w bazie danych, np. model newsów)
  • views.py: plik zawierający kod widoków - funkcji lub klas, które spinają wszystko i zwracają pod podpięty adres URL kod HTML podstrony
  • tests.py: ten plik może zawierać testy aplikacji. Nie jest wymagany choć w przyszłości przy tworzeniu bardziej złożonych aplikacji będą wskazane (na razie pomijamy ten plik).

Plik manage.py to w uproszczeniu lokalny odpowiednik django-admin.py. Można za jego pomocą tworzyć kolejne aplikacje, jak i wykonywać inne polecenia, o których dowiemy się za chwilę.

Aplikacje mogą zawierać dodatkowe pliki i katalogi (np. z szablonami) - o tym za chwilę, więc bez nerwów :)

Konfiguracja projektu w settings.py

Kolejny etap to konfiguracja bazy danych i innych ustawień w pliku settings.py. W tym artykule skorzystam z bazy SQLite konfigurując ją tak:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'blog.sqlite',
        # The following settings are not used with sqlite3:
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
    }
}

Jak widzimy dla SQLite wystarczy podać typ bazy danych i nazwę pliku. Dla pozostałych (np. MySQL, PostgreSQL) trzeba podać nazwę użytkownika, jego hasło, jak i stworzyć bazę danych o podanej w konfiguracji nazwie.

W pliku settings.py mamy wiele opcji, każda opisana w komentarzu. Nie trzeba wszystkiego od razu sprawdzać i zmieniać. Ograniczę się do najbardziej podstawowych.

Zmieniamy domyślny język na polski: LANGUAGE_CODE = 'pl' oraz ustawiamy strefę czasową na TIME_ZONE = 'Europe/Warsaw'.

Ostatni element to INSTALLED_APPS - lista zainstalowanych aplikacji. Stworzyliśmy aplikację "news" i żeby projekt ją "widział" musimy dodać ją do listy:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'news',
)

Mając gotową konfigurację możemy utworzyć podstawowe tabele w bazie danych (te używane przez Django). Robimy to poleceniem:

python manage.py syncdb

Polecenie to służy do tworzenia tabel z "nowych" modeli. Gdy tworzymy nową aplikację z nowymi modelami ponownie odpalamy to polecenie by stworzyć brakujące tabele w bazie danych.

W czasie wykonywania tego polecenia za pierwszym razem Django spyta nas, czy chcemy stworzyć konto superużytkownika, który będzie miał dostęp do panelu admina:

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):

Wpisujemy "yes" i następnie podajemy logi, adres email oraz hasło użytkownika.

Serwer deweloperski

Django posiada wbudowany prosty serwer, który służy do odpalania projektu. Nie potrzebujemy żadnego innego serwera (jak np. Apache). By uruchomić serwer deweloperski wystarczy w katalogu projektu wydać polecenie:

python manage.py runserver

Strona będzie dostępna pod adresem http://localhost:8000/

W warunkach produkcyjnych - gdy serwis jest skończony i dostępny w sieci nie używa się tego deweloperskiego serwera, tylko właśnie serwery takie jak Apache, Nginx odpowiednio skonfigurowane do obsługi projektu Django. Serwer deweloperski nie wymaga konfiguracji i ułatwia pracę programistom.

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 (odkomentuj linie dotyczące panelu admina):
from django.conf.urls import patterns, include, url

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
)
Pod adresem http://localhost:8000/admin/ dostępny będzie Panel Admina, do którego logujemy się danymi podanymi przy tworzeniu konta superużytkownika. Po zalogowaniu zobaczymy coś takiego:
Panel Admina Django
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('Nazwa Kategorii', max_length=100)
    slug = models.SlugField('Odnośnik', unique=True, max_length=100)
    icon = models.ImageField('Ikonka Kategorii', upload_to='icons',
                              blank=True)

    class Meta:
        verbose_name = "Kategoria"
        verbose_name_plural = "Kategorie"

    def __unicode__(self):
        return self.name


class News(models.Model):
    title = models.CharField('Tytuł', max_length=255)
    slug = models.SlugField('Odnośnik', max_length=255, unique=True)
    text = models.TextField(verbose_name='Treść')
    categories = models.ManyToManyField(Category, verbose_name='Kategorie')
    posted_date = models.DateTimeField('Data dodania', auto_now_add=True)

    class Meta:
        verbose_name = "Wiadomość"
        verbose_name_plural = "Wiadomości"

    def __unicode__(self):
        return self.title

Mamy model "Category" czyli kategorie wiadomości. Każda kategoria posiada nazwę ("name"), odnośnik ("slug", nazwa pozbawiona znaków niedopuszczanych w URLach - np polskich znaków), oraz ikonę - "icon".

Model wiadomości jest podobny - tytuł, odnośnik, treść ("text"), lista kategorii ("categories") oraz data dodania.

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. Django samo zajmie się stworzeniem tabel i obsługą relacji. Opis wszystkich pól i argumentów jakie przyjmują dostępny jest w oddzielnym artykule.

Praktycznie każde pole ma jako pierwszy argument podaną czytelną dla człowieka nazwę, np "Tytuł". To wartość argumentu "verbose_name", który używany jest w panelu admina. Zamiast wyświetlać surową nazwę możemy podać coś bardziej zrozumiałego. Tak samo klasy meta określają nazwy modelu używane w panelu - liczba pojedyncza i mnoga. Metoda __unicode__ zwraca tekstową wartość jaka będzie używana jako domyślny tekst dla rekordu modelu. W przypadku kategorii będzie to nazwa, a w przypadku wiadomości - tytuł.

Pole ImageField to specjalne pole tekstowe pozwalające przesłać na serwer plik graficzny. upload_to wskazuje katalog na pliki, a blank ustawione na False powoduje iż pole to jest opcjonalne.

Gdy mamy gotowy model możemy stworzyć tabele. Wystarczy ponownie wykonać:
python manage.py syncdb

Panel Admina dla modeli

Dla Django 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

from news.models import *


admin.site.register(Category)
admin.site.register(News)
W panelu admina powinniśmy zobaczyć nasze modele:
Modele aplikacji widoczne w panelu admina django
Możemy teraz dowolnie zarządzać danymi w tych modelach.
Dodawanie nowej kategorii
Panel Admina posiada bardzo szerokie możliwości dopasowywania. Za pomocą klasy dziedziczącej po "admin.ModelAdmin" 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 *


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


class NewsAdmin(admin.ModelAdmin):
    list_display = ('title', 'posted_date')
    prepopulated_fields = {'slug': ('title',)}


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" (tak że my nie musimy niczego tam wpisywać). Dodając nazwę kategorii ("name") automatycznie wstawiony zostanie przefiltrowany tekst do pola odnośnika "slug". Podobnie dla wiadomości.
Generowanie sluga w akcji
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 - obiekt "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 news/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 import patterns, include, url

from django.contrib import admin
admin.autodiscover()


urlpatterns = patterns('',
   url(r'^admin/', include(admin.site.urls)),
   url(r'^/?$', 'news.views.index'),
)
Reguła mapująca ma postać:
url(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:
Wykonany widok w przeglądarce

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('-posted_date')
    return render_to_response('index.html',
            {'news': news},
            context_instance=RequestContext(request))
Jak widać pobieramy wszystkie wiadomości, sortujemy je malejąco po dacie dodania i wynik przekazujemy do szablonu:
<h1>Moja Strona </h1>
{% for entry in news %}
    <h3>{{ entry.title }}</h3>
    {{ entry.text|safe }}<br />
    {{ entry.posted_date|date:"Y.m.d H:i" }}
{% endfor  %}
Listowanie wiadomości w akcji
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 oraz przykłady).
blog comments powered by Disqus

Kategorie

Strony