Twoja pierwsza aplikacja w Django, część 2
Tłumaczenie: Marcin Sztolcman <marcin {} urzenia // net>
Poprawki: Maciej Litwiniuk <maciej // litwiniuk {} galdomedia // pl>
Ta część tutoriala zaczyna się w miejscu, w którym skończyła się część pierwsza.
Będziemy kontynuować budowę aplikacji webowej - sondy - i skupimy się na
automatycznie generowanym panelu administracyjnym.
Założenia
Generowanie panelu administracyjnego dla klientów aby mogli dodawać, edytować i
usuwać treść jest żmudną pracą która nie wymaga zbyt dużej kreatywności. Z tego
właśnie powodu Django stara się zautomatyzować tworzenie interfejsu
administracyjnego.
Django był pisany w środowisku publicystów, gdzie bardzo ważnym było oddzielenie
części zarządzającej stroną od publicznej. Osoby zarządzające stroną używają
systemu aby dodawać nowe historie, wydarzenia, punktacje sportowe etc, a treść
ta była prezentowana czytelnikom. Django rozwiązuje problemy z związane
tworzeniem uniwersalnych paneli administracyjnych na potrzeby edycji treści.
Panel administracyjny nie jest przeznaczony do użytku przez osoby odwiedzające
naszą stronę - jest dla osób zarządzających tą stroną.
Aktywacja panelu administracyjnego
Część administracyjna Django jest domyślnie wyłączona - można ją opcjonalnie włączyć.
Aby aktywować interfejs administracyjny dla swojej instalacji, trzeba wykonać trzy
kroki:
Dodać "django.contrib.admin" do ustawień INSTALLED_APPS.
Wykonać komendę python manage.py syncdb. Jako, że dodałeś nową aplikację do
INSTALLED_APPS, tabele w bazie danych muszą zostać uaktualnione.
Popraw swój plik mysite/urls.py oraz odkomentuj linię znajdującą się pod
“Uncomment this for admin:”. Ten plik jest plikiem konfiguracyjnym dla URLi
Twojej strony - będziemy zgłębiać jego tajniki w następnej części tutoriala.
Na tą chwilę wystarczy Ci wiedzieć, że rzutuje on adresy URL na Twoją aplikację.
Po dokonaniu wyżej opisanych zmian powinieneś plik urls.py który jest podobny do tego:
from django.conf.urls.defaults import *
# Odkomentuj dwie linie pod spodem aby włączyć aplikacje admina:
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
# Przykład:
# (r'^mysite/', include('mysite.foo.urls')),
# Odkomentuj linie admin/doc pod spodem
# oraz dodaj 'django.contrib.admindocs'
# do INSTALLED_APPS aby włączyć dokumentacje admina:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Odkomentuj linie pod spodem aby włączyć aplikacje admina:
(r'^admin/(.*)', admin.site.root),
)
(Wytłuszczone linie, są liniami które powinny być odkomentowane aby włączyć aplikacje admina)
Uruchomienie serwera deweloperskiego
Uruchommy serwer deweloperski i przyjrzyjmy się stronie administracyjnej.
Przypomnij sobie z części pierwszej, że serwer deweloperski uruchamiałeś poleceniem:
python manage.py runserver
Teraz otwórz przeglądarkę internetową i przejdź do “/admin/” w swojej lokalnej
domenie — np. http://127.0.0.1:8000/admin/. Powinieneś zobaczyć ekran logowania
do aplikacji administracyjnej.
Obejrzymy panel admina
Spróbuj teraz się zalogować. (Stworzyłeś konto super użytkownika w części pierwszej, pamiętasz?)
Powinieneś ujrzeć stronę główną panelu administracyjnego Django:
Powinieneś zobaczyć również kilka innych typów edytowalnych treści, w tym grupy,
użytkowników oraz strony. To jest podstawowa funkcjonalność, którą Django
dostarczana domyślnie.
Modyfikacja sondy z panelu admina
Ale gdzie jest nasza sonda? Nie ma jej przecież w panelu administracyjnym.
Trzeba zrobić jedną rzecz: “poinformować” aplikacje admina Django że obiekty typu Poll
mają interface admina. Stwórz plik o nazwie admin.py w Twojej aplikacji polls i zmień go aby wyglądał tak:
from django.contrib import admin
from mysite.polls.models import Poll
admin.site.register(Poll)
Teraz odśwież stronę panelu, by zobaczyć zmiany. Zauważ, że nie musiałeś
ponownie uruchomić serwera deweloperskiego — serwer automatycznie przeładuje
projekt, więc wszelkie zmiany będą od razu widoczne w Twojej przeglądarce.
Badanie funkcjonalności admina
Teraz, gdy model Poll został zarejestrowany, Django wie, że ma
wyświetlić go w panelu:
Kliknij “Polls”. Jesteś teraz na wykazie wszystkich sond. Ta strona pokazuje
wszystkie sondy znajdujące się w bazie danych i pozwala wybrać jedną z nich do
edycji. Teraz znajduje się tam tylko “Jak leci?” - czyli sonda którą utworzyliśmy
w pierwszej części tutoriala:
Kliknij “Jak leci?” aby poddać ją edycji:
Rzeczy które warto zauważyć:
- Formularz został wygenerowany automatycznie na podstawie informacji z modelu
sondy
- różnym rodzajom pól modelu (model.DateTimeField, model.CharField) odpowiadają
różne kontrolki HTML. Każdy typ pola wie jak ma zostać wyświetlony w panelu
administracyjnym
- do każdego pola DateTimeField dodawane są dodatkowe przyciski. Dla daty
jest to “Today” (“Dzisiaj”) wraz z przyciskiem wyświetlającym okienko z mini
kalendarzem, natomiast dla pola “Time” (“Czas”) są przypisane przyciski
“Now” (“Teraz”) oraz drugi, służący do pokazania okienka z listą najczęściej
używanych określeń czasu.
Dolna część strony daje kilka opcji:
- Save (Zapisz) — zapisuje zmiany i wraca do listy obiektów danego rodzaju.
- Save and continue editing (Zapisz i kontynuuj edycję) — zapisuje zmiany i
przeładowuje stronę dla tego obiektu
- Save and add another (Zapisz i dodaj nowe) — zapisuje zmiany i przenosi do
nowego, pustego formularza odpowiedniego dla danego rodzaju obiektu.
- Delete (Usuń) — wyświetla ekran potwierdzający usunięcie obiektu.
Zmień datę publikacji (“Date published”) sondy poprzez kliknięcie skrótów
“Today” (“Dzisiaj”) i “Now” (“Teraz”). Następnie kliknij “Save and continue
editing” (“Zapisz i kontynuuj edycję”). Teraz wybierz “History” (“Historia”)
w prawym górnym rogu strony. Zobaczysz listę zmian dla tego obiektu dokonanych
w panelu administracyjnym Django, wraz z datą i godziną zmiany oraz loginem
osoby dokonującej tą zmianę:
Dostosowywanie panelu administracyjnego
Poświęć kilka minut na podziwianie kodu, którego wcale nie musiałeś napisać.
Kiedy wywołujesz admin.site.register(Poll), Django zgadnie jak ma wyświetlić model w adminie.
Często będziesz chciał kontrolować jak admin działa i wygląda. Zrobisz to mówiąc Django jakie opcje
chcesz zarejestrować na obiekcie.
Poprawmy go nieco. Możemy zmienić kolejność pól poprzez dodanie parametru
Zobaczmy jak to działa przez zmianę kolejności pól w formularzu edycji.
Podmień linie admin.site.register(Poll) na:
class PollAdmin(admin.ModelAdmin):
fields = ['pub_date', 'question']
admin.site.register(Poll, PollAdmin)
Powtórz ten wzorzec — stwórz obiekt model admin, przekaż go jako drugi argument do
admin.site.register() — za każdym razem gdy chcesz stworzyć opcje admina dla obiektu.
To spowodowało przesunięcie pola “Pub date” na górę:
Nie ma to większego znaczenia przy tylko dwóch polach, jednak dla formularzy z
większą ilością pól ustawienie intuicyjnej kolejności jest ważne ze względów
używalności takiego formularza.
A skoro już mówimy o formularzach z większą ilością pól, możesz chcieć je
podzielić na zestawy:
class PollAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date']}),
]
admin.site.register(Poll, PollAdmin)
Pierwszym elementem w każdej tupli (krotce) w atrybucie fieldsets jest nazwa
zestawu. Teraz formularz wygląda tak:
Możesz przypisać do każdego zestawu konkretną klasę języka HTML. Django posiada
wbudowaną obsługę klasy "collapse" która wyświetla wybrany zestaw pól jako
początkowo zwinięte. Jest to użyteczne gdy mamy długi formularz z kilkoma polami
które są rzadziej używane:
class PollAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
Dodawanie obiektów powiązanych
Ok. Mamy już w panelu nasze sondy. Ale każda sonda (Poll) ma kilka
odpowiedzi (Choices), a w panelu nie są one wyświetlane.
Jeszcze.
Są 2 sposoby na naprawienie tego problemu. Pierwszym jest zarejestrowanie obiektu Choice z adminem
tak samo jak zrobiliśmy to z obiektem. Tak by to wyglądało:
from mysite.polls.models import Choice
admin.site.register(Choice)
Teraz odpowiedzi do sondy są dostępne w panelu. Formularz dodawania odpowiedzi
(“Add choice”) wygląda tak:
W powyższym formularzu pole “Poll” jest polem wyboru zawierającym wszystkie
sondy w bazie. Django wie, że pole ForeignKey powinno być reprezentowane
w panelu administracyjnym jako pole <select>. W naszym przypadku tylko
jedna sonda chwilowo została zapisana.
Zwróć uwagę na odnośnik “Add another” (“Dodaj inną”) znajdujący się obok pola
“Poll”. Każdy obiekt powiązany kluczem obcym (ForeignKey) z innym obiektem
dostaje taki link automatycznie. Jeśli klikniesz “Add another”, zobaczysz
okienko (popup) z formularzem do dodawania sond. Jeśli dodasz nową sondę za
pomocą tego okienka i klikniesz “Save”, Django zapisze nową sondę w bazie danych
oraz uaktualni pole wyboru znajdujące się w formularzu odpowiedzi (“Choice”).
Powyższy sposób nie jest najbardziej efektywną metodą dodawania obiektów
odpowiedzi do systemu. Byłoby wygodniej, jeśli mógłbyś dodawać odpowiedzi
do sondy bezpośrednio z formularza w którym tworzysz nową sondę. Skoro tak,
to spróbujmy to wykonać.
Usuń wywołanie register() dla modelu Choice. Następnie zmień rejestracje modelu Poll:
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class PollAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['question']}),
('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
]
inlines = [ChoiceInline]
admin.site.register(Poll, PollAdmin)
Powyższa zmiana informuje Django: “Obiekty odpowiedzi są edytowane z poziomu
formularza sond. Domyślnie dostarcz 3 zestawy pól odpowiedzi.”
Załaduj stronę “Add poll” żebyśmy mogli sprawdzić jak to wygląda:
Działa to w następujący sposób: są tam 3 pola odpowiedzi — jak zostało ustalone
przez opcję extra — ale za każdym razem gdy wrócisz do strony już
stworzonego obiektu, dostaniesz kolejne pole odpowiedzi (tzn. nie ma na sztywno
ustawionego ograniczenia co do ilości powiązanych obiektów które można dodać).
Jest tylko jeden mały problem: wyświetlenie wszystkich powiązanych wpisów
zabiera mnóstwo miejsca na ekranie. Z tego powodu, Django pozwala na inny
sposób wyświetlenia wewnętrznie powiązanych obiektów;
musisz tylko zmienić deklaracje ChoiceInline:
class ChoiceInline(admin.TabularInline):
#...
Z TabularInline (zamiast StackedInline), wtedy powiązane obiekty
będą wyświetlane w bardziej skomasowany, tabelaryczny sposób:
Modyfikacja listy obiektów
Teraz, kiedy strony edycji i dodawania sondy wyglądają tak jak powinny,
spróbujmy poprawić stronę z listą sond.
Tak to wygląda obecnie:
Domyślnie, Django pokazuje reprezentację str() każdego obiektu. Oczywiście
można to trochę dostosować, tak, żeby wyświetlał pożądane przez nas pola.
Aby to zrobić, użyj opcji list_display, która jest krotką zawierającą nazwy
pól do wyświetlenia jako kolumny na stronie z listą sond:
class PollAdmin(admin.ModelAdmin):
# ...
list_display = ('question', 'pub_date')
Dla sprawdzenia jak się sprawuje ta opcja, dodajmy tam naszą metodę
was_published_today z pierwszej części tutoriala:
class PollAdmin(admin.ModelAdmin):
# ...
list_display = ('question', 'pub_date', 'was_published_today')
Teraz nasza strona z listą sond wygląda tak:
Możesz kliknąć na nagłówku każdej z kolumn aby posortować listę sond po
określonym parametrze — nie dotyczy to kolumny was_published_today,
ponieważ sortowanie z użyciem własnych metod nie jest obsługiwane przez Django.
Zauważ też że nagłówek kolumny dla pola was_published_today jest domyślnie
nazwą danej metody (z podkreślnikami zamienionymi na spacje).
Można to też zmienić poprzez dodanie atrybutu short_description dla danej
metody:
def was_published_today(self):
return self.pub_date.date() == datetime.date.today()
was_published_today.short_description = 'Published today?'
Teraz dodajmy kolejne usprawnienia do naszej listy: filtry (“Filters”). Dodaj
następującą linię do PollAdmin:
list_filter = ['pub_date']
To spowodowało pojawienie się panelu bocznego “Filter” który pozwala na
filtrowanie listy sond po polu pub_date:
Rodzaj wyświetlanych filtrów zależy od rodzaju pola po którym chcemy filtrować.
Ponieważ pub_date jest polem typu DateTimeField, Django wie że potrzebne
będą opcje “Any date” (“Każda data”), “Today” (“Dzisiaj”), “Past 7 days”
(“Ostatnie 7 dni”), “This month” (“Ten miesiąc”), “This year” (“Ten rok”).
Zaczyna wyglądać coraz lepiej. Dodajmy możliwość wyszukiwania:
search_fields = ['question']
Na górze strony pojawiło się teraz pole wyszukiwarki. Gdy zostanie tam wpisana
jakaś fraza, Django przeszuka pola question. Możesz użyć tylu pól ile
potrzebujesz — aczkolwiek pamiętaj, że Django używa tutaj kwerendy SQL LIKE,
więc umieszczaj tu tylko te pola których potrzebujesz.
Na koniec, ponieważ nasza sonda posiada daty, powinniśmy pogrupować nasze sondy
po tym właśnie polu. Dodaj poniższą linijkę:
date_hierarchy = 'pub_date'
Teraz na górze strony pojawiły się pola ułatwiające nawigację po dacie. Na
samej górze pokazane są dostępne lata. Później miesiące i dni.
Pozostało mi jeszcze poinformować Ciebie, że lista sond jest automatycznie
dzielona na strony mieszczące domyślnie do 50 obiektów. Stronicowanie listy
sond, pole wyszukiwarki, filtry, grupowanie po datach i sortowanie po kolumnach
wspópracują ze sobą tak jak tego oczekujesz.
Upiększanie panelu administracyjnego
Tak naprawdę, napis “Django administration” na górze każdej strony jest nieco
mylący. Jest tylko “wypełniaczem”.
Bardzo łatwo jest je zmienić korzystając z systemu szablonów Django. Panel
administracyjny Django jest tworzony przez samo Django, więc nic dziwnego,
że korzysta ze swojego własnego systemu szablonów.
Otwórz swój plik ustawień (mysite/settings.py, pamiętaj) i spójrz na opcję
TEMPLATE_DIRS. Jest to krotka, przechowująca ścieżki do katalogów które
Django ma sprawdzać w poszukiwaniu szablonów.
Domyślnie TEMPLATE_DIRS jest puste. Dodajmy tam linię aby poinformować
Django gdzie ma szukać szablonów:
TEMPLATE_DIRS = (
"/home/my_username/mytemplates", # Change this to your own directory.
)
Skopiuj teraz plik admin/base_site.html z domyślnego katalogu szablonów
Django (django/contrib/admin/templates) do podkatalogu admin w którymkolwiek
z katalogów które ustawiłeś w TEMPLATE_DIRS. Na przykład jeśli umieściłeś
w TEMPLATE_DIRS linijkę /home/my_username/mytemplates, jak powyżej,
to skopiuj django/contrib/admin/templates/admin/base_site.html do
katalogu /home/my_username/mytemplates/admin/base_site.html. Nie zapomnij
o tym podkatalogu admin.
Teraz wystarczy zmienić skopiowany plik zastępując domyślne teksty Django
swoimi.
Zauważ, że każdy domyślny szablon Django może zostać nadpisany. Aby to zrobić,
zrób dokładnie to samo co zrobiłeś przed chwilą z base_site.html —
skopiuj go z domyślnego katalogu do swojego, i wykonaj zmiany.
Uważni czytelnicy mogą zapytać: skoro TEMPLATE_DIRS był domyślnie pusty,
jak Django wyszukiwał domyślne szablony do panelu administracyjnego ?
Odpowiedź: domyślnie, Django automatycznie szuka w podkatalogu templates/
każdej aplikacji. Zajrzyj do loader types documentation (en), żeby dowiedzieć
się więcej.
Zmiana wyglądu listy projektów
Kontynuując temat zmian wyglądu, możesz także dostosować dla siebie stronę z
listą dostępnych aplikacji (indeks) panelu administracyjnego.
Domyślnie pokazywane są wszystkie dostępne aplikacje, zgodnie z Twoimi
ustawieniami INSTALLED_APPS, w kolejności alfabetycznej. Możesz sobie zażyczyć konkretnego wyglądu tejże strony. Poza tym,
indeks jest prawdopodobnie najważniejszą częścią panelu, więc powinien być
prosty w użyciu.
Szablon który tutaj użyjemy to admin/index.html (wykonaj te same czynności
co przy admin/base_site.html w poprzedniej sekcji — skopiuj go z katalogu
domyślnego do swojego). Następnie otwórz ten plik - zobaczysz że jest w nim
użyta zmienna szablonu: app_list. Jest to ten magiczny
element, który zwraca listę zainstalowanych aplikacji Django. Zamiast używać
tego taga, możesz wstawić “na sztywno” odnośniki do konkretnych stron panelu
odpowiedzialnych za konkretne obiekty - i ułożyć je tak jak uważasz, że będzie
najlepiej.
Aby dowiedzieć się więcej o dostosowywaniu wyglądu panelu administracyjnego
Django, zajrzyj na Django admin CSS guide (en).
Kiedy już poznasz panel administracyjny Django, przeczytaj
trzecią część tego tutoriala aby zacząć tworzyć publicznie widoczną stronę
aplikacji.
Jeżeli zauważyłeś błędy w tłumaczeniu dokumentacji proszę zgłoś je nam.