0
Guido van Rossum
ABC
Przykład
Skryptowy
Duck typing
2 != “2”

 Silne typowanie
Wcięcia są znaczące
Klasy są obiektami



Refleksja

           Metaklasy
                         Otwarte klasy



    Metaprogramowanie
Refleksja
Klasy są obiektami
Multiparadygmatowy
Przykład obiektowy
Przykład funkcyjny
Przykład AOP
wyrażenia regularne

                                        daty

                                 liczby zespolone

    ...
Benchmarki
Na podstawie testów ze strony
http://shootout.alioth.debian.org/
Java > Python > Ruby
Perspektywy
Beautiful is better than ugly
Explicit is better than implicit
Readability counts
Special cases aren’t special enough to
           break the rules



  Although practicality beats purity
Errors should never pass silently
Unless explicitly silenced
There should be one - and preferably
  only one - obvious way to do it
Although that way may not be obvious
     at first unless you're Dutch
http://stepniowski.com
    /x/python.html




               Ćwiczenia!
Adrian Holovaty
Rekomendowane przez Guido
MVC
Wzorzec Active Record
ORM
ORM
PostgreSQL
     MySQL
     SQLite
     Oracle
     DB2
Wspierane bazy danych
Szablony
Szablony
Widoki
Różne                Date based
direct_to_template   archive_index
redirect_to          archive_year
object_list          ...
Wzorce URL
Struktura katalogów
Formularze
LAPD
Chciałem umieścić tutaj jakieś
benchmarki, ale i tak byście w
       nie nie uwierzyli
Dlaczego?
Aplikacje - killer feature
Tagowanie
               Wyszukiwanie
                                     Paginacja
               pełnotekstowe

 Rejest...
Czym jest aplikacja?
Django skłania do podziału
   projektu na aplikacje
Zarządzanie użytkownikami

                            Flatpages

                      Internacjonalizacja

        Wysył...
Admin
Admin
Admin
1.1 β
http://stepniowski.com
       /x/pid.html




           Ćwiczenia!
Dzięki!
http://stepniowski.com

  http://zuber.blip.pl
Wprowadzenie do Pythona i Django
Wprowadzenie do Pythona i Django
Wprowadzenie do Pythona i Django
Wprowadzenie do Pythona i Django
Wprowadzenie do Pythona i Django
Wprowadzenie do Pythona i Django
Wprowadzenie do Pythona i Django
Wprowadzenie do Pythona i Django
Upcoming SlideShare
Loading in...5
×

Wprowadzenie do Pythona i Django

3,730

Published on

Published in: Technology, Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,730
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
16
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide
  • Django to framework do tworzenia stron internetowych dla perfekcjonistów z terminami. Ta prezentacja ma przekonać was do użycia Django w następnym projekcie webowym. Skupiam się tu bardziej na przedstawieniu zalet Pythona i Django, niż na nauce kodowania w nich. Od tego są doskonałe tutoriale na http://docs.python.org i http://docs.djangoproject.com/. Zakładam też, że słuchacze umieją już programować (czytaj: znają co najmniej jeden język programowania wysokiego poziomu i umieją w nim zaimplementować algorytm quick sort).
  • Django napisane jest w języku programowania Python. Serwisy internetowe pisane przy użyciu Django również pisze się głównie w Pythonie. (Zazwyczaj powyżej 60% kodu serwisu to kod Pythona. Reszta to szablony Django, HTML, CSS i SQL). Zaczniemy od krotkiego wprowadzenia do tego języka.
  • Twórcą Pythona i jego BDFL (Benevolent Dictator for Life - osoba mająca decydujący głos w decyzjach dotyczących rozwoju języka) jest Guido van Rossum. Jest on Holendrem. Obecnie pracuje w Google nad dalszym rozwojem Pythona.
  • Python został stworzony pod koniec lat ‘80 jako następca języka ABC. W związku z tym jest starszy od Javy! Język ABC był językiem stworzonym do nauki programowania, tak samo jak Pascal, BASIC czy AWK. Po ABC Python odziedziczył m.in. prostotę oraz kontrowersyjną składnię, o której za chwilę.
  • W tym momencie typowy programista powinien już zacząć się nudzić. Pora więc na pokazanie przykładowego kodu! Slajd przedstawia implementację algorytmu quick sort w 5 linijkach (nie licząc komentarzy). Kod wykorzystuje obcięcia (list[] w linijkach 6-8) oraz list comprehensions ([x for x in list] w linijkach 6 i 8). Te drugie zostały zapożyczone z języka Haskell. Całość powinna być dość czytelna.
  • Python to jeden z 3 oficjalnych języków Google, obok C++ i Javy. Dużo usług Google jest tworzone w Pythonie, a potem przepisywane na inne języki dla zwiększenia wydajności. Inne firmy i organizacje używające Pythona to m.in. NASA, Pixar, Rackspace i Canonical (twórcy Ubuntu).
  • Python jest językiem skryptowym. Programy w tym języku nie muszą być kompilowane. Jednak podczas uruchomienia skryptu w Pythonie tworzone są pliki z bytecode. Pozwala to na szybsze załadowanie tego skryptu w przyszłości przez interpreter. Instrukcje Pythona są bardzo wysokiego poziomu. Szacuje się, że przy normalnym stosowaniu jedna instrukcja w języku Python odpowiada ~20 instrukcjom w C.
  • Python jest językiem dynamicznie typowanym, tak jak np. PHP czy Ruby. Często jest to określane jako duck typing, czyli “Jeśli coś chodzi jak kaczka i kwacze jak kaczka to jest kaczką”. Typy zmiennych są sprawdzane dopiero w czasie wykonywania skryptu.
  • Nie należy mylić dynamicznego typowania ze słabym typowaniem. Python jest językiem silnie typowanym, w przeciwieństwie do np. PHP czy C. Oznacza to, że nigdy nie zostanie wykonana instrukcja na typie, który jej nie obsługuje. Python zgłosi przy takiej próbie błąd wykonania.
  • W Pythonie wcięcia są znaczące. Ta cecha języka budzi najwięcej kontrowersji. Została ona odziedziczona po ABC. Przyzwyczajenie się do wcięć wymaga trochę czasu, ale jest tego warte. Ostatecznie jest to jedna konwencja kodowania mniej do sprzeczania się przy programowaniu zespołowym.
  • Python jest bardzo dynamicznym językiem, tak samo jak Ruby i w przeciwieństwie do np. Smalltalka czy PHP. Utrudnia to stworzenie dobrego IDE, ale pozwala na stosowanie wielu technik określanych wspólnie jako metaprogramowanie. Na dalszych slajdach wspomnę w skrócie o refleksji i tym, że klasy są obiektami.
  • Praktycznie wszystkie cechy programu w Pythonie można łatwo poznać z wnętrza tego programu, podczas jego wykonywania. Refleksja jest w Pythonie bardzo zoptymalizowana. Powyższy kod wypisuje wszystkie metody danego obiektu wraz z ich opisami. Zwróćcie uwagę na jego ogólność. Obiekt w jego rozumieniu możeby być modułem, klasą, listą albo słownikiem. Taką ogólność otrzymujemy praktycznie za darmo, dzięki dynamicznemu typowaniu.
  • Wszystko w Pythonie jest obiektem - w tym również klasy i funkcje. Pozwala to na przekazywanie klas i funkcji jako argumenty funkcji oraz na (uwaga!) tworzenie nowych klas i funkcji w trakcie działania programu. Powyższy kod implementuje wzorzec projektowy Fabryka. Znany z Javy i C++, w Pythonie jest on całkowicie nadmiarowy, ponieważ sama klasa jest fabryką obiektów.
  • Python pozwala na programowanie przy użyciu wielu różnych konwencji, tak jak np. C++. Tak jak w innych językach skryptowych można w nim pisać imperatywnie, ale przydaje się to tylko przy najprostszych skryptach.
  • Wspominałem już o tym, że wszystko w Pythonie jest obiektem. Na slajdzie jest kod bardzo prostej klasy implementującej interfejs stosu. Jako kontener storage wspierający stos używamy listy (inicjalizowanej konstrukcją []). Implementacja obiektów opiera się na słownikach, co objawia się np. możliwością dynamicznego dodawania atrybutów do nich. __init__ to konstruktor (jak w Javie).
  • Funkcje są w Pythonie obiektami, można więc przekazywać je jako argumenty i zwracać z funkcji. Kod ze slajdu zawiera implementację funkcji map w Pythonie. Druga implementacja używa bardzo wygodnych list comprehensions.
  • Podaję jeszcze przykład Aspect Oriented Programming. Powyższy program dodaje logowanie do wszystkich funkcji klasy Stack (opisanej na slajdzie 15). Zauważcie użycie domknięcia, refleksji oraz dynamicznego typowania do osiągnięcia celu.
  • Filozofia Pythona to “batteries included!”. Python posiada bardzo obszerną bibliotekę standardową zawierającą m.in. implementacje wielu usług sieciowych (SMTP, HTTP...), parsery XML, xUnit, klienta bazy SQLite i obsługę archiwów ZIP. Liczby zespolone są wbudowane w Pythona. Wyrażenie (2 + 3j) oznacza liczbę zespoloną z częścią rzeczywistą 2 i częścią urojoną 3.
  • Wszyscy kochają benchmarki, mimo że nie należy im ufać, bo mierzą wydajność języków/frameworków w bardzo specyficznych warunkach. Pora na przedstawienie benchmarków Pythona.
  • Porównanie Pythona 2.6 z Java 6 i Ruby 1.8.7 ze strony http://shootout.alioth.debian.org/. Testy użyte w tym benchmarku są bardzo niskopoziomowe, stąd tak duże różnice w prędkości Pythona i Javy.
  • Na podstawie benchmarków można uznać, że Java jest szybsza od Pythona, który jest za to szybszy od Ruby. Jeżeli chodzi o ilość linii kodu potrzebnych do zapisania kodu programu, zwycięzcami są Python i Ruby. Java wymaga 2-3x więcej kodu do wykonania podobnych operacji, mimo że testy są bardzo niskopoziomowe.
  • Nie należy się bać o przyszłość języka Python. Ma on oficjalne wsparcie Google. Rozwijają się alternatywne do CPython implementacje: IronPython pod .NET i Jython pod JVM. Niedawno Google udostępniło też hosting dla serwisów webowych w Pythonie: Google App Engine. Stronę obsługującą do kilku milionów odsłon miesięcznie można tam trzymać za darmo. Powyżej tego limitu płaci się tylko za wykorzystane zasoby.
  • Uruchomcie interaktywną powłokę Pythona i wpiszcie w niej komendę “import this”. Wyświetli się wam 19 zdań znanych jako The Zen of Python. Przyjrzymy się najciekawszym z nich.
  • Matematyczne piękno tego kodu wynika raczej z algorytmu, ale zauważcie jak mało znaków jest tutaj nadmiarowych. Praktycznie pseudokod.
  • Zauważcie, że zakresy są explicite (słowo self). Importowanie modułów i używanie obiektów i funkcji z zaimportowanych modułów również jest explicite.
  • Pierwsza linia tego kodu wypisuje proste “Hello world”. Porównajcie ją z odpowiednim programem w C++ lub Javie. Wcięcia bardzo pomagają w zwiększeniu czytelności kodu. Pomagają w tym również deklaratywne konstrukcje, takie jak sum i list comprehensions.
  • Python nie posiada oddzielnego typu dla znaków. Znak to ciąg znaków o długości jeden. Ale pragmatyzm przeważa nad purytanizmem: dla zachowania zgodności z C udostępnione zostały funkcje ord i chr.
  • Wszystkie sytuacje wyjątkowe powodują w Pythonie zgłoszenie wyjątku. Wyjątki są stosowane nawet w sytuacjach takich, jak wyczerpanie się iteratora.
  • Oczywiście Python pozwala na wyciszanie wyjątków konstrukcją try...except...finally. Można w ten sposób zaimplementować np. opcjonalne importowanie.
  • There should be one - and preferably only one - obvious way to do it. Jest to zasada będąca dokładnym przeciwieństwem filozofii języka Perl (od którego Ruby bierze swoje korzenie). Bardzo zwiększa ona łatwość zrozumienia cudzego kodu.
  • “Ale ta droga nie zawsze jest oczywista, chyba że jesteś Holendrem”. Wystarczy spojrzeć na składnię operatora trynarnego w Pythonie, by to zobaczyć :-)
  • Ćwiczenia z Pythona znajdziecie na stronie http://stepniowski.com/x/python.html. Mam nadzieję, że uporamy się z nimi w ciągu 15 minut. Ćwiczenia są dość proste, ale nie znacie jeszcze języka, więc mogą wam sprawić trudności. Nie wahajcie się zadawać pytań!
  • To tyle, jeżeli chodzi o wprowadzenie do Pythona. Wracamy do Django!
  • Twórcą Django jest Adrian Holovaty. Framework Django został stworzony na potrzeby gazety Lawrence Journal. Powstał on równolegle do Ruby on Rails, obrał też inną drogę rozwoju.
  • Framework Django wziął swoją nazwę od muzyka jazzowego Django Reinhardta. Nawiązania do jazzu są dość częste w środowisku Djangonautów. Django zostało wyekstrahowane z CMS Ellington. Ellington to też muzyk jazzowy :-)
  • Od momentu usunięcia magii (zachowań implicite, których działanie było trudne do przewidzenia dla osób nie znających kodu frameworku) jeszcze przed wersją 1.0 Django jest rekomendowane przez Guido jako “najbardziej Pythoniczne”. Django stara się przestrzegać Zen of Python. Guido sam napisał w nim system do code review dla Pythona (działający na Google App Engine).
  • Kto używa Django? Dla równowagi postanowiłem umieścić tutaj tylko polskie serwisy. Od góry są to: Oiola (platforma do organizowania eventów i konferencji), Wydarzysie.net (powiadomienia o ważnych i ciekawych wydarzeniach w okolicy), Szarada.net (serwis dla miłośników krzyżówek), grono.net (pierwszy polski serwis społecznościowy), plom (serwis pozwalający na prowadzenie miniblogów, podobny do Blipa i Twittera), Ocenfotke.pl (ocenianie zdjęć użytkowników), wolnelektury.pl (biblioteka internetowa z tekstami polskich lektur szkolnych, stworzona przeze mnie), strona Super Expressu. Należy pamiętać, że są to tylko przykłady. Wiele serwisów z musu pominąłem.
  • Django jest frameworkiem MVC (Model, View, Controller), tak jak np. Ruby on Rails. Wyraźnie oddzielone są w nim kawałki kodu odpowiedzialne za logikę biznesową i przechowywanie danych (Model), wyświetlanie tych danych (View) oraz wybór operacji do wykonania i obsługę interfejsu użytkownika (Controller).
  • Trochę oszukałem. Twórcy określają Django jako framework MTV (Model, Template, View). Bierze się to stąd, że we frameworkach webowych MVC programista tak naprawdę nie pisze Controllera - jest on dostarczany przez sam framework (w Rails Controller w tym sensie to Routes). Jest to zastosowanie wzorca Front Controller.
  • Modele w Django są tworzone według wzorca Active Record. Modele to obiekty, które mają określone atrybuty oraz potrafią wczytać i zapisać się do bazy danych.
  • Wczytywaniem modeli z bazy danych zarządza ORM (Object-Relational Mapper). To właśnie ORM odpowiada za największy wzrost produktywności programisty we frameworkach webowych. ORMy dzielą się na te od najprostszych (ActiveRecord w Ruby on Rails) do najbardziej skomplikowanych (Hibernate dla Javy, SQLAlchemy dla Pythona). ORM Django jest gdzieś po środku.
  • ORM Django obsługuje skomplikowane zapytania ze złączeniami i wieloma warunkami. Obsługuje też transakcje. Pozwala również na wybieranie tylko interesujących nas atrybutów. Kiedy ORM zawodzi, łatwo jest wrócić do zwykłego SQL.
  • Django wspiera tylko relacyjne bazy danych. Oficjalnie wspierane są PostgreSQL, MySQL, SQLite i Oracle. IBM pracuje obecnie nad backendem Django do DB2. Na ćwiczeniach będziemy używać SQLite, którego klient wbudowany jest w Pythona w wersji 2.5 i nowszych.
  • Szablony. {{ zmienna }} wstawia zmienną w miejsce wystąpienia. {% tag %} wykonuje zaś określoną w nim czynność. Django zawiera bogatą bibliotekę wbudowanych tagów. Np. {% url %} wstawia adres URL danego widoku (o tym za chwilę). {% block %} definiuje zaś blok treści, który można potem nadpisywać (bardzo ważna funkcja, o tym też za chwilę!). Możliwe jest również tworzenie własnych tagów.
  • Killer feature Django to możliwość dziedziczenia szablonów. W tym przykładzie dziedziczymy większość z szablonu base.html (przedstawionego na slajdzie 44), ale nadpisujemy blok content, wstawiając w jego miejsce listę obiektów. Dzięki temu nie musimy powtarzać w różnych miejscach tego samego kodu.
  • Opisałem już modele i szablony. Czas na warstwę, która je połączy: widoki. Widoki to zwykłe funkcje Pythona, które jako pierwszy argument biorą obiekt klasy HttpRequest i zwracają obiekt klasy HttpResponse. W tej prostocie tkwi ich siła.
  • Jak wykorzystać to, że widoki to zwykłe funkcje? Wiele widoków da się uogólnić. Django jest rozprowadzane z biblioteką ogólnych widoków.
  • Opisaliśmy już wszystkie warstwy MTV, ale trzeba jeszcze umieć wybrać widok do wyświetlenia. Tutaj na pomoc przychodzi wzorzec z pliku urls.py. Określa on mapowanie pomiędzy adresami URL a widokami.
  • Całość. Tak wygląda struktura katalogów przykładowego projektu. Nie opisałem jeszcze pliku settings.py - jest on odpowiedzialny za globalne ustawienia projektu, takie jak np. użytkownik i hasło do bazy danych, czy położenie katalogu z szablonami. settings.py napisany jest w Pythonie, co daje nam do dyspozycji całą siłę ekspresji tego języka przy pisaniu bardziej złożonych plików ustawień.
  • Pozostała jeszcze kwestia walidacji danych wprowadzanych przez użytkowników. Jeśli ktoś programował w PHP, wie jak męczące i błędogenne może to być. Na pomoc przychodzi pakiet forms. Formularze zajmują się walidacją danych, ale potrafią się również wyświetlać. Ich składnia podobna jest do składni modeli. Dostępny jest skrót do tworzenia formularzy na podstawie modeli (klasa ArtistForm na dole slajdu).
  • Wdrożenie Django. LAPD = Linux, Apache, PostgreSQL, Django. Django można połączyć z Apache przez CGI, FastCGI, mod_wsgi, mod_python. Jest to stos tak samo elastyczny jak LAMP.
  • Chciałem umieścić tutaj jakieś benchmarki, ale i tak byście w nie nie uwierzyli. Faktem jest, że o ile Python jest wolniejszy od wielu języków, w tym Javy, Django prześciga większość frameworków (w tym Symfony, CakePHP, Ruby on Rails i frameworki J2EE).
  • Dlaczego Django jest tak szybkie, mimo że Python jest względnie wolny? Moim zdaniem tajemnica tkwi w dynamiczności tego języka. Pierwsze: Dużo rzeczy dostępnych za darmo w Pythonie trzeba implementować samemu w innych językach (jak PHP czy Java), przez co traci się na prędkości. Drugie: globalna optymalizacja.
  • Pozostał do omówienia jeszcze jeden killer feature Django. Są to aplikacje.
  • Każdy serwis internetowy posiada wiele ortogonalnych funkcji. Wiele z tych funkcji nie zależy za bardzo od typu serwisu. Dlaczego implementować je stale od nowa? Inne frameworki mają od tego różne systemy pluginów. Django ma aplikacje.
  • Aplikacja jest podobna do małej strony internetowej: może zawierać własne modele, widoki, szablony, formularze oraz wzorce URLi. Na slajdzie znajduje się hierarchia katalogów ściśle tajnego kodu serwisu WolneLektury.pl ;-)
  • Django od początku skłania programistę do myślenia w kategorii ortogonalnych aplikacji. W pliku settings.py definiujemy listę aplikacji składających się na projekt. Domyślnie stworzony projekt zawiera już 4 aplikacje, odpowiedzialne za obsługę sesji HTTP, autoryzację użytkowników i ogólne powiązania pomiędzy modelami.
  • Django, tak samo jak Python, przestrzega filozofii “batteries included!”. Pozwala na bardzo wiele rzeczy out of the box (większość jest zaimplementowana jako aplikacje i da się je wyłączyć).
  • Jeżeli aplikacje to killer feature Django, to co można powiedzieć o adminie? Admin to aplikacja rozprowadzana razem z Django, pozwalająca na szybkie stworzenie panel administracyjny naszego serwisu. Domyślnie admin służy do prostego zarządzania modelami w sensie CRUD, ale jest bardzo rozszerzalny. Właściwie można go traktować jako framework wewnątrz frameworku.
  • Kilka screenshotów z admina.
  • Prostota podłączenia własnych modeli do admina.
  • W momencie, gdy to piszę, na stronie http://djangoproject.com można już ściągnąć Django 1.1 beta. Ta wersja wprowadza wiele nowych funkcji, takich jak: obsługa ETagów, funkcje agregacji w ORMie, opóźnionym pobieranie pól z bazy danych, możliwość wykonywania akcji na wielu obiektach naraz w adminie.
  • Ćwiczenia z Django znajdziecie na stronie http://stepniowski.com/x/pid.html. Pamiętajcie, w razie jakichkolwiek problemów, pytajcie!
  • Mam nadzieję, że prezentacja ta zachęciła was do wypróbowania Pythona i Django. W razie dodatkowych pytań możecie mnie znaleźć na Blipie (gdzie występuję jako ^zuber). Więcej namiarów na mnie znajdziecie na mojej stronie domowej http://stepniowski.com.
  • Transcript of "Wprowadzenie do Pythona i Django"

    1. 1. Guido van Rossum
    2. 2. ABC
    3. 3. Przykład
    4. 4. Skryptowy
    5. 5. Duck typing
    6. 6. 2 != “2” Silne typowanie
    7. 7. Wcięcia są znaczące
    8. 8. Klasy są obiektami Refleksja Metaklasy Otwarte klasy Metaprogramowanie
    9. 9. Refleksja
    10. 10. Klasy są obiektami
    11. 11. Multiparadygmatowy
    12. 12. Przykład obiektowy
    13. 13. Przykład funkcyjny
    14. 14. Przykład AOP
    15. 15. wyrażenia regularne daty liczby zespolone wielowątkowość wieloprocesowość SQLite archiwa zip kryptografia JSON XML usługi sieciowe testowanie Batteries included!
    16. 16. Benchmarki
    17. 17. Na podstawie testów ze strony http://shootout.alioth.debian.org/
    18. 18. Java > Python > Ruby
    19. 19. Perspektywy
    20. 20. Beautiful is better than ugly
    21. 21. Explicit is better than implicit
    22. 22. Readability counts
    23. 23. Special cases aren’t special enough to break the rules Although practicality beats purity
    24. 24. Errors should never pass silently
    25. 25. Unless explicitly silenced
    26. 26. There should be one - and preferably only one - obvious way to do it
    27. 27. Although that way may not be obvious at first unless you're Dutch
    28. 28. http://stepniowski.com /x/python.html Ćwiczenia!
    29. 29. Adrian Holovaty
    30. 30. Rekomendowane przez Guido
    31. 31. MVC
    32. 32. Wzorzec Active Record
    33. 33. ORM
    34. 34. ORM
    35. 35. PostgreSQL MySQL SQLite Oracle DB2 Wspierane bazy danych
    36. 36. Szablony
    37. 37. Szablony
    38. 38. Widoki
    39. 39. Różne Date based direct_to_template archive_index redirect_to archive_year object_list archive_month object_detail archive_week create_object archive_day update_object archive_today delete_object object_detail Widoki uogólnione
    40. 40. Wzorce URL
    41. 41. Struktura katalogów
    42. 42. Formularze
    43. 43. LAPD
    44. 44. Chciałem umieścić tutaj jakieś benchmarki, ale i tak byście w nie nie uwierzyli
    45. 45. Dlaczego?
    46. 46. Aplikacje - killer feature
    47. 47. Tagowanie Wyszukiwanie Paginacja pełnotekstowe Rejestracja Powiadomienia FAQ Przetwarzanie Ocenianie zdjęć Zarządzanie użytkownikami Ortogonalne funkcje serwisu
    48. 48. Czym jest aplikacja?
    49. 49. Django skłania do podziału projektu na aplikacje
    50. 50. Zarządzanie użytkownikami Flatpages Internacjonalizacja Wysyłanie e-maili Komentarze Sitemaps RSS geodjango Batteries included!
    51. 51. Admin
    52. 52. Admin
    53. 53. Admin
    54. 54. 1.1 β
    55. 55. http://stepniowski.com /x/pid.html Ćwiczenia!
    56. 56. Dzięki! http://stepniowski.com http://zuber.blip.pl
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×