14 sierpnia 2007

Zaczynam z Django 6 - prawdziwa strona II

Kolejną właściwością szablonów jest dostęp do elementów słowników, obiektów i tablic. Większości wyda się to oczywiste, ale warto o tym wspomnieć.

Słownik:



In [15]: from django.template import Context,Template
In [16]: t = Template("""Jestem {{ osoba.nazwisko }}. {{osoba.imie}} {{osoba.nazwisko}}
....: W najnowszym filmie bede mial {{osoba.liczbaZyc}} zyc""")
In [18]: james = {'imie': 'James', 'nazwisko': 'Blond', 'liczbaZyc': '5'}
In [19]: c = Context({'osoba': james})
In [20]: t.render(c)
Out[20]: 'Jestem Blond. James Blond\nW najnowszym filmie bede mial 5 zyc'



Obiekt (oczywiście do obiektów własnych klas odwołujemy się tak samo):



In [24]: from django.template import Context,Template
In [25]: import datetime
In [26]: d = datetime.date(2007, 7, 14)
In [27]: d.month
Out[27]: 7
In [28]: t = Template('Miesiac {{ date.month }} roku Panskiego {{ date.year }}.')
In [29]: c = Context({'date': d})
In [30]: t.render(c)
Out[30]: 'Miesiac 7 roku Panskiego 2007.'
In [31]: c = Context({'date': datetime.date(2007, 6, 14)})
In [32]: t.render(c)
Out[32]: 'Miesiac 6 roku Panskiego 2007.'



Elementy tablicy (i wywołanie metody upper - można wołać metody, ale tylko bezparametrowe, jak najbardziej można używać kropki wielokrotnie, nie używa się nawiasów przy wywołaniu ):



In [48]: from django.template import Template, Context
In [49]: t = Template('Teraz prezentujemy agenta o numerze dwa: {{ agenci.2.upper }}.')
In [50]: t.render(Context({'agenci': ['James', 'Bolo', 'Olo']}))
Out[50]: 'Teraz prezentujemy agenta o numerze dwa: OLO.'



Jak na warstwę prezentacji, wymienione elementy to naprawdę sporo. W przypadku gdyby ktoś bał się, że mu wystąpi konflikt nazw, kolejność szukania elementu po kropce jest następująca (dla a.b): klucz w słowniku (a["b"]), atrybut obiektu (a.b), wywołanie metody(a.b()), odwołanie do tablicy (a[b]).
Jeszcze słówko o obsłudze wyjątków w metodach. Można spowodować, żeby wyjątek był zignorowany (oczywiście nie jest to dobry sposób obsługi każdego wyjątku). W szablonach Django dzieje się tak wtedy, kiedy obiekt wyjątku ma ustawioną specjalną zmienną: silent_variable_failure = True
Można także zabezpieczyć się przed wywołaniem metody (na przykład takiej, która ma efekty uboczne):



def zapis(self):
zapis.alters_data = True



Kolejnym istotnym elementem jest zachowanie szablonów w momencie odwołania się do nieistniejącej zmiennej. Jeżeli nie zostanie zmieniona konfiguracja Django, to błędne odwołania są ignorowane (pusty string). Warto o tym pamiętać, choćby ze względu na rozróżnianie wielkości liter.

16 czerwca 2007

Najnowsze Django w Ubuntu

Dzisiaj pojawiło się nowe Django w Ubuntu (7.04, Feisty Fawn) - Version 0.96-1, czyli zgodnie z aktualnie wydaną wersją. Miło, bo oszczędzi to kilku problemów (jak np. ten opisany przeze mnie z krótkimi URL-ami). Pozwoli to też wzorować się dokładniej na DjangoBook.

09 czerwca 2007

Wracam na niusy

Postanowiłem zacząć znowu czytać niusy, oczywiście RSS dalej traktując jako podstawowe źródło informacji. Ale przeprosiłem się Usenetem i starym dobrym NNTP. Zachęcił mnie do tego występ Michała Rutkowskiego w telewizorni, przypomniałem sobie jak kiedyś na łamach pl.rec.sport.koszykowka dyskutowaliśmy np. o Timie Duncanie, o którym zresztą MR wczoraj sporo mówił. I od razu włączyłem tina (best ever NNTP reader) i uporządkowałem listę grup. Na razie tylko python, donosy i koszykówka. I już przyniosło to efekty, znalazłem ciekawy link: Zestaw filmów o Pythonie, między innymi Django (tylko instalacja). Jest też kilka innych interesujących kategorii.

02 czerwca 2007

Zaczynam z Django 5 - prawdziwa strona

W kolejnym podejściu chcę generować "prawdziwe" strony. Teraz trzeba już wykorzystać system szablonów oferowanych przez Django. W końcu po to on jest. Po to jest on. Z lektury czwartego rozdziału DB dowiedziałem się, że w szablonach: dostęp do zmiennych uzyskuje się poprzez napisanie {{ nazwa_zmiennej }}, bloki kodu oznaczamy tak {% instrukcje do wykonania %} i mamy dostęp do filtrów (przy pomocy znaku |, to chyba najciekawszy element) wbudowanych i własnych. Dozwolone sa zarówno bloki kodu z instrukcjami warunkowymi if else endif jak i pętlami for (np. {% for category in categories %}) Wszystkie te możliwości spróbuje sprawdzić i pokazać w najbliższym czasie.

Kolejna ciekawostka, którą oferują szablony użyte w Django, to możliwość wygenerowania obiektu szablonu poprzez podanie łańcucha znaków zawierającego szablon (oprócz tego oczywiście jest możliwość podania ścieżki do pliku zawierającego szablon, ale to standard). Zaczynam klasyczne testy: ./manage.py shell a potem: from django.template import Template, potem t = Template("Jestem {{ nazwisko }}. {{imie}} {{nazwisko}}") i print t co spowoduje nam tylko wyświetlenie gdzie znajduje się obiekt t. Z tego co piszą w DB to szablony są prekompilowane do wewnętrznej formy, gotowej do wygenerowania strony. W związku z tym błąd w szablonie (np. t = Template('{% bledna instrukcja %} ')), objawia się już w momencie powoływania obiektu szablonu do życia.

Generowanie strony z szablonu odbywa sie w kontekście, który jest reprezentowany przez obiekt klasy Context. W poniższym kodzie krótka prezentacja (kod przeklejony bezpośrednio z konsoli, uznałem że ta forma prezentacji będzie lepsza, oczywiście wpisujemy to, co jest po dwukropku):



In [27]: from django.template import Context,Template
In [28]: t = Template("Jestem {{ nazwisko }}. {{imie}} {{nazwisko}}")
In [29]: c = Context({"nazwisko": "Blond", "imie": "James"})
In [30]: t.render(c)
Out[30]: 'Jestem Blond. James Blond'



Oczywiście warto sprawdzić, co się stanie, jak kontekst nie będzie miał zdefiniowanej jakiejś zmiennej:



In [33]: from django.template import Context,Template
In [34]: t = Template("Jestem {{ nazwisko }}.{{imie}}{{nazwisko}}")
In [35]: c = Context({"nazwisko": "Blond"})
In [36]: t.render(c)
Out[36]: 'Jestem Blond.Blond'


Jak widać, nic złego sie nie stało. Wygenerowany został pusty napis. Moim zdaniem, to plus (CakePHP generował, o ile dobrze pamiętam, błąd w takiej sytuacji). Projektant strony może więc ją spokojnie rozszerzać o nowe elementy odwołujące się do jeszcze nie zdefiniowanych zmiennych i nie czekać na programistę.

Ostatni element w tym wpisie to umożliwienie interaktywnego testowania wielolinijkowych szablonów (informacja przydatna dla tych co wcześniej nie korzystali z Pythona), wielolinijkowe łańcuchy znaków umieszczamy po prostu pomiędzy potrójnymi cudzysłowami """długi łańcuch""":



In [39]: from django.template import Context,Template
In [40]: t = Template("""Jestem {{ nazwisko }}.{{imie}}{{nazwisko}}
....: W najnowszym filmie bede mial {{liczbaZyc}} zyc
....: Co Ty na to""")
In [42]: c = Context({"nazwisko": "Blond", "imie": "James", "liczbaZyc": 5})
In [43]: t.render(c)
Out[43]: 'Jestem Blond.JamesBlond\nW najnowszym filmie bede mial 5 zyc\nCo Ty na to'



Przykłady zawierają powtórzenia (importy, ponowne definicje obiektów) wyłącznie dla pokazania pełnego obrazu tego co się dzieje w programie. W trakcie jednej sesji oczywiście nie ma potrzeby wielokrotnego importowania klas czy tworzenia tego samego szablonu.

Czwarty rozdział DjangoBook jest całkiem spory, więc jego zawartość rozciągnie się na kilka wpisów, w których sukcesywnie będę poszerzał informacje o szablonach.

15 maja 2007

Zaczynam z Django 4 - pierwsza strona

Czas najwyższy, żeby zobaczyć efekty jakiejś własnej pracy, bo jak do tej pory, to głównie automaty wykonywały za mnie wszystkie czynności.
Czas wykorzystać konfiguracje URL-i, którą już raz zmieniałem (plik urls.py). Pierwsza wprawka w DB (rozdział 3) po uproszczeniu przeze mnie wygląda następująco:


from django.http import HttpResponse
import datetime

def current_datetime(request):
html = "Jest %s" % datetime.datetime.now()
return HttpResponse(html)


Zapisujemy to do pliku views.py.
Warto sobie znowu na boku odpalić terminal i ./manage.py shell a potem: from mdjango.mbegin.views import *
(wszystkie kolejne sprawdzenia będę najpierw przeprowadzał w konsoli, więc nie będę juz pisał o jej odpalaniu).
Odpalamy current_datetime(), powinien nam się pojawić błąd. Wynika on z tego, że próbowałem wykorzystać konsolę do wypisania HTTPResponse.
Teraz już zmiana konfiguracji URL-i: dodajemy import pliku z widokami i konfiguracje przekierowania w przypadku wywołania adresu http://localhost:8080/czas/.
plik urls.py wygląda teraz tak:


from django.conf.urls.defaults import *
from mdjango.mbegin.views import *

urlpatterns = patterns('',
(r'^czas/', current_datetime),
(r'^admin/', include('django.contrib.admin.urls')),
)


I powoduje pokazanie....błędu. Przy okazji okazuje się jak django pokazuje błedy, jak dla mnie całkiem przejrzyście i tego właśnie bym oczekiwał od informacji o błędzie. Jest stos, jest zapytanie, jest konfiguracja. Chyba nie muszę już pisać o kolejnym plusie. Zauważyłem również możliwość przełączania pomiędzy trybami oglądania informacji o błędzie. Sam błąd to: AttributeError at /czas/ 'function' object has no attribute 'rindex' oznacza on, że DB jest do przodu w stosunku do mojego Ubuntu. Tak jak napisałem URL-e docelowe, można je pisać dopiero od wersji 0.96 a ja mam 0.95. Na razie daruję sobie podnoszenie wersji (warto znać różne metody obejścia problemu). Rozwiazaniem jest napisanie nazwy funkcji jako stringa poprzedzonego nazwą aplikacji i modułu. Więc ostatecznie wygląda to tak:


from django.conf.urls.defaults import *
from mdjango.mbegin.views import *

urlpatterns = patterns('',
(r'^czas/', 'mbegin.views.current_datetime'),
(r'^admin/', include('django.contrib.admin.urls')),
)


Przy okazji upraszczania zrobiłem jeszcze jeden błąd: W ramach upraszczania nie napisałem parametru request dla funkcji current_datetime, jest on oczywiście potrzebny. Po poprawieniu usterek widać skromną, ale własną, pierwszą stronę wykonaną przy uzyciu django. Teraz już pójdzie z górki, ale to już w następnym odcinku. A na dzisiaj ostatni element, żeby mieć poprawny czas, trzeba ustawić TIME_ZONE = 'Europe/Warsaw' (lub jak kto woli mieć ustawione) w settings.py, no chyba, że ktoś mieszka w tej samej strefie czasowej co Chicago

07 maja 2007

Zaczynam z Django 3 - baza danych

Zaczynam z Django 3

Jako, że mam już wcześniej przygotowaną bazę danych, to warto byłoby z niej skorzystać. Do tego służy znalezione dopiero w 17 rozdziale DB python mysite/manage.py inspectdb, warto sobie przejrzeć co się produkuje na ekran, a potem w najprostszy sposób zapisać to do pliku z modelem: ./manage.py inspectdb > mbegin/models.py
(DB: python mysite/manage.py inspectdb > mysite/myapp/models.py). Generowane jest coś w tym stylu:


class Categorie(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(maxlength=600)
description = models.TextField(blank=True)
class Meta:
db_table = 'categories'

Ponieważ tabele miały nazwy przystosowane do innego frameworka, więc ich nazwy są w liczbie mnogiej. Wygląda na to, że Django korzysta z prostej zasady, odejmij od liczby mnogiej 's' i masz liczbę pojedynczą. Nie zawsze się to sprawdza, w DB piszą, żeby przejrzeć i oczyścić wygenerowany model, z pewnością to później uczynię, zgodnie z zasadami podanymi we wspomnianym rozdziale 17. Druga zastanawiająca rzecz, to wartość maxlength (w bazie pola są varchar(200) a w modelu 600), trzeba będzie doczytać o sposobie kodowania znaków. Niestety bezpośrednio w DB nic na ten temat nie piszą.
Żeby sprawdzić, czy model działa można skorzystać z ./manage.py shell. Jeżeli wcześniej zainstalowaliśmy sobie IPythona, to mamy w tej chwili całkiem sympatyczne środowisko pracy z bazą danych, a właściwie z jej modelem. Śmiem przypuszczać, że będzie to też dobre miejsce do np. uruchamiania unit testów. Żeby skorzystać z modelu jakiejś tabeli, starczy wpisać from project.app.models import nazwa_modelu czyli na przykładfrom mdjango.mbegin.models import Categorie, a później już można Categorie.objects.values() (wartości z rekordów), albo Categorie.objects.count() (liczba rekordów). Kolejny duży plus dla Django, można sprawdzić od razu jak działa model, zanim go użyjemy w aplikacji. Na razie phpmyadmina użyłem tylko do sprawdzenia, czy model się zgadza, większość potrzebnych operacji można teraz z poziomu powłoki wykonać, mając pewność, że jest się podłączonym do właściwej bazy itp.

04 maja 2007

Zaczynam z Django 2

Jedziemy dalej, zgodnie z tym co napisane na utworzonej wcześniej (http://piotrbla.blogspot.com/2007/05/zaczynam-z-django.html) stronie projektu. W pliku settings.py ustawiamy fragment dotyczący bazy danych (od DATABASE_ENGINE do DATABASE_PORT. Dwa ostatnie, na czas testów, można zostawić puste. Przy okazji warto zauważyć, że plik z ustawieniami to źródła w Pythonie, więc obowiązują wszystkie reguły języka. Dzięki temu piszemy też cały czas w jednym języku. Oprócz bazy danych ustawiam też dane administratora.

Po ustawieniu bazy danych generujemy pierwszą aplikację: ./manage.py startapp mbegin (na wygenerowanej stronie projektu: python mdjango/manage.py startapp [appname]). Powstaje katalog (u mnie mbegin) w którym są puste pliki dla modeli i widoków (models.py i views.py). Przy generacji mały problem z kodowaniem pliterek w nazwisku administratora, na razie odpuszczam (rezygnuje z pliterek), jak później będzie trzeba to zgłębię temat.

Kolejną rzeczą dającą szybkie efekty jest panel administratora (mały chwilowy przeskok do 6 rozdziału DB). W pliku settings.py w sekcji INSTALLED_APPS dodajemy wpis 'django.contrib.admin', później uruchamiamy ./manage.py syncdb (DB: python manage.py syncdb) co powoduje wygenerowanie tabel administracyjnych w bazie danych. Przy pytaniu o superusera warto od razu go utworzyć (później robi się to według DB przy pomocy skryptu /django/contrib/auth/create_superuser.py. Ja przy pomocy locate create_superuser.py znalazłem ten skrypt w następujących lokalizacjach:
/var/lib/python-support/python2.4/django/contrib/auth/create_superuser.py
/var/lib/python-support/python2.5/django/contrib/auth/create_superuser.py
/usr/share/python-support/python-django/django/contrib/auth/create_superuser.py


Według DB trzecim etapem generowania panelu jest dopisanie do pliku urls.py (w projekcie)
urlpatterns = patterns('',
(r'^admin/', include('django.contrib.admin.urls')),
)

a w moim przypadku było to odkomentowanie tej linijki w rzeczonym pliku. Próbuję sprawdzić, stwierdzam, że niepotrzebnie wcześniej restartowałem mini serwer (zmiany pojawiają się od razu po nagraniu pliku). Niestety (jednak to jakoś przeżyję) nowe zmiany spowodowały, że dotychczasowa strona główna zgłasza błąd (w tym miejscu warto zauważyć, że wszystkie komunikaty o Django jakie do tej pory widziałem prowadziły do rozwiązania). Działa natomiast podstrona /admin
http://localhost:8080/admin/ logujemy się, i ukazuje się w pełni GOTOWA estetyczna strona administracyjna, z możliwościami przeglądania i filtrowania danych, dodawania grup, użytkowników itp. Innymi słowy, coś co powinno być wszędzie.

Podstawy zarządzania użytkownikami mam całkowicie z głowy, co w porównaniu z innymi frameworkami znowu wygląda obiecująco.

Zaczynam z Django

Zacząłem właśnie próbować użyć django, o którym tak wiele dobrego się naczytałem (choćby tutaj).

Chciałbym przy pomocy django zrealizować jeden mały, ciekawy i innowacyjny projekt, o którym myślę od dawna. Jak django będzie współpracował, to czekają już kolejne pomysły.

Taka ciekawostka: przy okazji rozmowy o django, wyszedł jak zwykle problem wymowy. Dobrze poinformowane źródła mówią, że mówi się dżangoh (bezdźwięczne d, oh przechodzące w oł ;) ).

Jako towarzysza wędrówki wybrałem: DjangoBook, rozwiązań problemów będę poszukiwał najpierw w tej dostepnej na licencji GNU książce. Na chwilę obecną jeszcze nie wszystkie jej rozdziały są napisane (większość jest), więc czasami trzeba będzie wesprzeć się wyszukiwarką.

Zestaw startowy już mam: Linux (Ubuntu DD->EE->FF), Python, Django, Mysql. Wszystko do znalezienia w synapticu. Oczywiście można używać django z innymi popularnymi bazami danych (jak i bez żadnej bazy, co też kiedyś zweryfikuje). W DjangoBooku (dalej DB) piszą, żeby sprawdzić czy ma się mysql-python, ja mam w Ubuntu python-mysqldb i wygląda, że to właśnie ten pakiet. Dodatkowo oczywiście warto sprawdzić czy działa phpmyadmin (niestety, na chwilę obecną pod Linuksa brak IMHO lepszego narzędzia, można jeszcze z kexi próbować).

Warto wspomnieć przy okazji o mojej znajomości Pythona. Napisałem kilka (naprawdę kilka) skryptów (wielkości, jak ja to mówie, ekranu). Trochę czytałem o języku (w tym jedną średniej wielkości książkę), interesuje się nim od dawna. Zawodowo programowałem jednak zawsze w innych językach. To co _mi_ w Pythonie podoba się najbardziej to załączone bateryjki i wymuszanie wcięć (jak ktoś poprowadzi zajęcia z programowania dla poczatkujących w jakimkolwiek języku C-podobnym, to będzie wiedział, dlaczego to jest plus języka). Znajomość Django: słyszałem, że dobry i nic więcej. Czyli: Python 4/10, Django 1/10.

Bazę danych do mojego projektu mam juz prawie gotową, więc raczej nie będę się nad nią specjalnie pochylał.

Na początek w terminalu przechodzimy do swojego katalogu ze stronami (u mnie public_html i piszemy: django-admin startproject mdjango (w DB piszą: django-admin.py startproject mysite, ale instalacja django z pakietu dodała gdzieś elegancko skrypt i wie, że to pythonem się uruchamia). Z tego co na chwilę obecną wiem, Django może przechowywać kilka aplikacji w jednym projekcie.
Projekt przechowuje ustawienia bazy danych, opcji Django i aplikacji.
Powstają następujące pliki: __init__.py, manage.py, settings.py, urls.py.
Jak będą potrzebne to napiszę do czego służą.
Tak powstałą stronę można od razu sprawdzić przy pomocy wbudowanego mini serwera http. Wystarczy go uruchomić (w katalogu mdjango): ./manage.py runserver (znowu DB podaje dłuższą wersję: python manage.py runserver). Ja akurat mam domyślny port (8000) zajęty, więc dostaje błąd: Error: That port is already in use. Port zmienia się trywalnie: ./manage.py runserver 8080 (DB: python manage.py runserver 8080). Po wejściu na http://localhost:8080/ widzimy od razu działającą stronę projektu ze wskazówkami. Czas na pierwszą ocenę: z kilku przeze mnie wypróbowanych frameworków (w tym RoR i CakePHP) Django na tym etapie wygrywa, czas dojścia do tego punktu był po prostu najkrótszy.

21 marca 2007

Kasowanie kopii zapasowych plików

Wiadomo, żeby usunąć pliki '*~' zawierające kopie zapasowe w jakimś katalogu piszemy rm *~ .*~, niektórzy lubią napisać jeszcze -Rf. Nie skasuje to nam jednak plików kopii zapasowych w podkatalogach. Żeby to wykonać, można użyć takiego magicznego polecenia:
find ./ -name '*~' | xargs rm -r

Można się tego nauczyć na pamięć, ale oczywiście warto sobie przygotować skrypcik o powyższej treści np. o nazwie rmbak (i przy pomocy polecenia chmod +x rmbak nadac mu atrybut wykonywalności). Dobrze jest tego typu skrypty umieszczać w katalogu ~/bin . Jeżeli programiki tam umieszczone nie uruchamiają się, należy do pliku ~/.bashrc (ewentualnie jak potrzebujemy to do ~/.bash_profile) dodać taki wpis:
if [ -d ~/bin ] ; then
PATH="${PATH}":
~/bin
fi
Próba kasowania w katalogu, który nie zawiera żadnych plików tymczasowych kończy się komunikatem: rm: missing operand, ja go traktuje jako informację, że nie było nic do skasowania. Jeżeli komuś to nie pasuje, to wystarczy dodać opcję -f(orce), czyli polecenie będzie wyglądać tak: find ./ -name '*~' | xargs rm -rf

12 marca 2007

Blogowanie

Zaczynam blogować. Wszyscy to robią, to mi też wolno czasem popisać. O czym? O wszystkim co podleci. Przede wszystkim ciekawe znaleziska z sieci, trochę programowanie, Linux i inne nerdowskie tematy. Czasem o polityce i rzetelności dziennikarskiej, a raczej jej braku, może o tematach społecznych.