Chętnie spotkałbym się z tymi programistami Delphi, którzy robią (zawodowo lub OMC zawodowo) w Pythonie. Właśnie nie dawno zobaczyłem posta Fiedzi na django-users, parę innych nazwisk też mi się wydaje znajomych...
Markdown to fajny wynalazek, ale zaskakująco niebezpieczny i to w miejscu, którego zwykle się nie spodziewamy... Wspomniał o tym jakiś czas temu Jeff Atwood przy okazji jakichś innych wynurzeń. Utkwiło mi to bardzo mocno w pamięci, pewnie dlatego, że kiedyś zdarzyło mi się popełnić aplikację podatną na XSS. Tak, nieumiejętnie (nazwałbym to bezmyślnie, ale nie jest moim zamiarem itd.) zastosowany markdown wystawi na niebezpieczeństwo także i Twój serwis. Zastanawiam się nad tym, jak zastosować do zmyślnie, bo chciałbym użytkownikom wMiastoWzięci.pl dać do ręki coś, co im się przyda, a jednocześnie nie pozwoli im na wyrządzenie żadnych szkód (obojętne, umyślnie czy nieumyślnie).
Pewnym rozwiązaniem mogłoby być oczyszczenie tekstu źródłowego przed zapuszczeniem na nim filtra markdown — ale to trochę przypomina wylewanie dziecka z kąpielą, bo wyłącza część użyteczności markdown. Z drugiej jednak strony, rozwiązanie Jeffa A. (czyszczenie tylko części HTML) nie wydaje mi się rozsądne, przede wszystkim z powodu ogromnego skomplikowania zagadnienia. Czyżby była to sytuacja bez wyjścia?
Dlaczego właśnie Python? Często sam zadaję sobie to pytanie i próbuję dać autorytatywną odpowiedź, biorąc pod uwagę mnogość języków, które znam i których używałem (zawodowo i hobbistycznie) w ciągu moich ponad 10 lat praktyki. W ostatnich dniach pojawiło się kilka głosów, które dają pewne sugestie co do możliwej odpowiedzi:
Jestem coraz bliżej odpowiedzi na moje pytanie.
Dziś o 8 rano w ośrodku na Radarowej zdałem egzamin teoretyczny na prawo jazdy B. Ciąg dalszy 2 grudnia o 19, także na Radarowej — będę zdawał egzamin praktyczny. Mam nadzieję, że strategia Bernarda Montgomery da mi równie dobre wyniki, jak dawała jemu: tylko miażdżąca przewaga jest przewagą wystarczającą.
Zdarzyło się tak, że zrobiłem literówkę w urlconfie i stało się, Google zaindeksowało mi stronę pod błędnym url-em. O ja nieszczęsna, ale przecież zdarza się w najlepszej rodzinie. Trzeba było zmontować jakiegoś redirecta. Co prawda Django ma jakąś swoją aplikację do redirectów (django.contrib.redirects), ale przecież nie o to chodzi, żeby Django robiło wszystko, skoro to taka drobnostka — przecież każdy serwer http ma coś do robienia redirectów, Lighttpd nie jest żadnym wyjątkiem. Trochę nad tym posiedziałem (bo orłem z wyrażeń regularnych to ja nie jestem...) i działa jak złoto:
$HTTP["host"] =~ "(^|\.)wmiastowzieci\.pl$" {
url.redirect = (
"/miajsca/$" => "/miejsca/",
)
}
Żeby było ciekawiej (choć to babol i w nowszym lighty będzie zmienione), lighty w tym momencie wysyła 301 (czyli permanent redirect) co akurat w moim przypadku robi dobrze, bo nie zamierzam więcej popełniać tej literówki. :)
To uczucie nieporównywalne z niczym: budujesz aplikację przez kilka tygodni lub miesięcu i przez cały czas zastanawiasz się czy ktoś będzie tego używał?. W takiej niepewności trwasz dopóki nie zauważysz, że jednak ktoś zdecydował się jej użyć, a wtedy... No i wtedy właśnie przychodzi ten strzał adrenaliny, który mogę porównać tylko z paroma rzeczami (niestety, nie mogę napisać, co to za rzeczy, bo każda z nich jest albo szkodliwa albo zakazana przez prawo — tę stronę przecież czytują dzieci...). Dziś rano spojrzałem w panel administracyjny jednego z moich prywatnych serwisów i poczułem właśnie TO.
Pomimo trzymania aplikacji w niemal całkowitej tajemnicy do czasu ukończenia prac (wiedziała o niej tylko moja żona i Google, o ile ktoś wiedział czego ma szukać), ktoś zajrzał na wMiastoWzięci.pl i dodał wydarzenie (choćby z tego powodu warte uwiecznienia). Nie będę tego ukrywał dłużej, to mój serwis. Wciąż jeszcze jest szlifowany, wciąż nie wszystko w nim działa, ale jak widać komuś to nie przeszkadzało. Co nie działa:
-
zgłaszanie obiektów (wydarzenia, zdjęcia, recenzje) do moderacji
-
komentarze do wydarzeń i miejsc
-
przeglądanie wielu etykiet na raz
Dla spragnionych informacji technicznych: serwis działa na Django-trunk, baza to MySQL 5.0 (z backendem MyISAM), deployment na FastCGI/lighttpd.
A skoro już poszło w świat, to skończył się luźny czas developmentu w modelu langsam, langsam i trzeba w szybkim tempie dorobić brakujące funkcje serwisu. ;)
Turbo Pascal jest dziś starszy, niż spora część programistycznego światka. Wspominam go z sentymentem, bo to był mój pierwszy język programowania, w który wsiąkłem na dobre (i na wiele lat). Nauczyłem się przy jego użyciu (a potem Delphi, poczynając od wersji 2) wielu rzeczy, na nim wyrosłem na dojrzałego programistę i w nim napisałem moje pierwsze aplikacje, używane przez innych ludzi. Na dobre skończyłem pisać w Delphi/Pascalu dopiero z końcem 2006 roku, więc pamięć jest jeszcze żywa.
Jak się ma 25 lat, to już można sobie golnąć. Zdrowie młodzieńca!
Pomimo tego, że robię w Django od paru lat, wciąż zdarzają mi się odkrycia na miarę archimedejskiej eureki. Dziś właśnie zauważyłem, że skrót render_to_response może przyjmować jako pierwszy argument nie tylko nazwę szablonu, ale także listę nazw szablonów. Dzięki temu wiekopomnemu odkryciu kod, który wyglądał dość marnie:
templates = [
'flagging/%s_flagging_form.html' % obj._meta.module_name,
'flagging/flagging_form.html',
]
template = loader.select_template(templates)
return HttpResponse(template.render(ctx))
teraz może wyglądać trochę ładniej:
templates = [
'flagging/%s_flagging_form.html' % obj._meta.module_name,
'flagging/flagging_form.html',
]
return render_to_response(templates, ctx)
Świadomie używam określeń ładnie i brzydko, bo chodzi tu jedynie o estetykę (obydwa warianty robią dokładnie to samo pod spodem).
Na swoje usprawiedliwienie mogę powiedzieć tylko tyle, że takie zachowanie render_to_response jest obecnie nieudokumentowane (ale zgłosiłem odpowiedniego patcha).
I'm pleased to announce my first (hopefully) reusable app for Django: django-confirmation. The idea for this app came from my personal need to handle confirming object's creation on one of my sites. I found few apps performing similar tasks, but both are targeting single classes of objects, while I needed more generic approach (I hate this word...) — there are several classes of objects that need to be confirmed separately but using the same mechanism.
The use case for this app is as follows:
-
non-registered/not-logged-in user creates an object;
-
application sends an email asking user to click (within configurable period of time) on provided link to make the object "active";
-
user clicks a link and makes the object "active" or
-
key expires after specified amount of time.
The implementation is based on what I found in other apps, specially django-registration and django-email-confirmation, but with added support for confirming generic Django model instances (as long as they can have different activity states, that is).
Django jest fantastyczne m.in. w tym, że istnieje masa podłączalnych aplikacji, które w sposób wystarczająco generyczny realizują często spotykane zadania, jak np. django-registration do rejestrowania użytkowników, czy django-tagging do etykietowania obiektów. Część z tych aplikacji jest naprawdę wysokiej jakości, w dodatku łatwo konfigurowalnych i możliwych do dopasowania w dość szerokim zakresie. Są jednak takie, które dobrze się zapowiadają od dłuższego czasu, jednak na tym się kończy. Co bardziej zaskakujące, wszystkie te potencjalnie użyteczne aplikacje pochodzą z projektu Pinax.
W jednym z projektów potrzebuję dodać funkcję powiadamiania użytkowników o wystąpieniu pewnych zdarzeń. Jest aplikacja django-notification, ale w stanie obecnym nie nadaje się do wykorzystania poza Pinaxem (lub w sposób jakkolwiek różny od tego, jak to jest robione w Pinaksie). Zgłoszone są problemy z tym związane, jednak zostały odłożone na lepsze czasy. Będę musiał wziąć kod django-notification i wzorując się na nim napisać swoją własną aplikacyjkę, bo na te lepsze czasy się nie doczekam.
Inny przykład. Niedawno potrzebowałem dodać do pewnego projektu możliwość tworzenia obiektów przez niezalogowanych użytkowników — wymagane jest wtedy podanie adresu email i potwierdzenie dodania obiektu przez standardowe kliknięcie w przesłany link. Znalazłem aplikację django-email-confirmation, która robi coś podobnego, ale nie nadaje się do potwierdzania jakichkolwiek innych obiektów, niż jej własne (a ja potrzebowałem zastosować ten mechanizm do 3-4 różnych klas obiektów). Trzeba było napisać własną, na szczęście okazało się to dość proste, przyjmując django-email-confirmation za wzór.
I to samo mam za każdym razem, gdy trafiam na aplikację, która mogłaby mi się przydać, a pochodzi z Pinaxa — bez zakodowania własnego rozwiązania bazującego na tym kodzie się nie obejdzie. Rozumiem, że Pinax jest rozwijany w normalny dla OS/FS sposób, to znaczy w czasie wolnym i nikt nie bierze za to pieniędzy, ale skoro tak to wygląda, to jaki jest sens wydzielać aplikacje jako niby reużywalne, skoro tak naprawdę nie dają się użyć nigdzie poza aplikacjami typu Pinaxa i ich reużywalność to głęboki mit?