Open Source

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.

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

Strona główna panelu administracyjnego

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:

Strona główna panelu administracyjnego, teraz z sondami

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:

Wykaz wszystkich sond

Kliknij “Jak leci?” aby poddać ją edycji:

Formularz edycji dla obiektu sondy

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

Historia sondy

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

Kolejność pól została zmieniona

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:

Formularz jest teraz podzielony na zestawy

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']}),
    ]
Zestaw pól jest teraz wstępnie zwinięty

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:

Strona administracyjna dla odpowiedzi

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:

Strona dodawania sondy ma teraz pole dodawania odpowiedzi

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:

Strona dodawania sondy ma teraz bardziej skomasowane pola odpowiedzi

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:

Strona listowania istniejących sond

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:

Lista sond, zaktualizowana

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:

Lista sond, zaktualizowana

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.

Pytania/Wsparcie

Jeżeli zauważyłeś błędy w tłumaczeniu dokumentacji proszę zgłoś je nam.