czwartek, 24 marca 2011

Nowe Django 1.3

Jakiś czas temu (prawie rok) pisałem w SDJ o tworzeniu aplikacji internetowych w Django. Kiedy powstawał ten artykuł, własnie wyszła beta 1.2. Wczoraj ukazała się stabilna wersja 1.3 frameworka a w niej sporo zmian. Pełen opis nowych funkcjonalności tu: http://docs.djangoproject.com/en/dev/releases/1.3/


Z najważniejszych zmian:

- widoki można tworzyć teraz jako klasy, odpowiednie klasy zastępują też generyczne widoki oparte o funkcje: http://docs.djangoproject.com/en/dev/topics/generic-views-migration/

- logger z poziomu frameworka:

import logging

logger = logging.getLogger(__name__)

....

logger.error('Coś poszło nie tak!')

- wygodniejsza obsługa plików statycznych (js, css, obrazki): http://docs.djangoproject.com/en/dev/howto/static-files/

- obsługa unittest2

- kontrolowanie zarządzania transakcją w widokach

- konfigurowalne delete-cascade

- ulepszone wbudowane tagi w szablonach

- klasa TemplateResponse

- ulepszona infrastruktura cache'owania

... i wiele innych. Zmiany wprowadzają też częściową niezgodność z poprzednimi wersjami Django.


Jak zainstalować najnowszą wersję Django?

1. Sprawdzamy gdzie w systemie mamy zainstalowane biblioteki dla Pythona
$ python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"

w moim wypadku otrzymałem:
 /usr/lib/python2.6/dist-packages


2. Ściągamy najnowsze Django

a) z SVN'a:

w katalogu gdzie chcemy mieć zawsze najświeższą wersję Django z gałęzi trunk wydajemy polecenie:
$ svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk
tworzymy dowiązeznie w katalogu z bibliotekami, zamiast SITE-PACKAGES-DIR wpisujemy to co dostaliśmy w kroku 1):
$ ln -s `pwd`/django-trunk/django SITE-PACKAGES-DIR/django
tworzymy dowiązanie do skryptu administracyjnego:
$ ln -s `pwd`/django-trunk/django/bin/django-admin.py /usr/local/bin

b) z paczki z aktualnym wydaniem:
$ wget http://media.djangoproject.com/releases/1.3/Django-1.3.tar.gz
$ tar xzvf Django-1.3.tar.gz
$ cd Django-1.3
$ sudo python setup.py install

3. Tworzymy nowy projekt 

$ django-admin.py startproject myproject
$ cd myproject
$ python manage.py runserver

Efekt:



poniedziałek, 14 marca 2011

gedit jak TextMate

Jak powszechnie wiadomo każdy prawdziwy railsowy programista ma Maca, a na nim TextMate'a. Ja prawdziwym railsowym programistą nie jestem, ale lubię jak mi się przyjemnie pracuje. Do szybkiej edycji kodu używam gedit'a - co dodatkowo nie czyni mnie prawdziwym linuksiarzem, skoro nie robię tego w emacsie, względnie vimie ;-)

Krótki przepis jak upiększyć nieco standardowy gnomowy edytor tekstu:

1. Instalacja czcionki Monaco:
$ wget http://jorrel.googlepages.com/Monaco_Linux.ttf
$ sudo mkdir /usr/share/fonts/truetype/custom/
$ sudo mv Monaco_Linux.ttf /usr/share/fonts/truetype/custom/
$ sudo fc-cache -f -v

2. Instalacja tematów:

Repozytorium git z tematami dla gedita:
https://github.com/mig/gedit-themes

Ściągamy paczkę z tematami i przenosimy w odpowiednie miejce:
$ wget --no-check-certificate https://github.com/mig/gedit-themes/tarball/master -O gedit-themes.tar.gz
$ sudo tar -xvzf gedit-themes.tar.gz 
$ sudo mv mig-gedit-themes-f9b4314/*.xml /usr/share/gtksourceview-2.0/styles/

sprzątamy po sobie:
$ sudo rmdir --ignore-fail-on-non-empty mig-gedit-themes-f9b4314 
$ sudo rm gedit-themes.tar.gz 

Mi przypadły do gustu tematy 'Oblivion', 'RailsCast' oraz 'Twilight'. Szczególnie ten ostatni pasuje do mojego pulpitu i motywu 'Ambiance' w Ubuntu.

3. Instalacja dodatkowych wtyczek
$ sudo apt-get install gedit-plugins
Warto włączyć takie wtyczki wspomagające programowanie jak: 'inteligentne spacje', 'komentowanie kodu', 'osadzony terminal', 'uzupełnianie nawiasów' czy 'wstawki'. Nietrudno znaleźć też w sieci wtyczki dedykowane dla RoR czy Django.

Efekt końcowy:

czwartek, 13 maja 2010

O Django w SDJ

Majowy numer Software Developer's Journal poświęcony niemalże w całości Pythonowi. Co w nim ciekawego?





  • Buildout - tworzenie wersji instalacyjnych dla aplikacji napisanych w Pythonie
  • Plone - jak zbudować firmowy intranet w oparciu o pythonowy CMS
  • Python 3 - co nowego w trzeciej wersji
  • Funkyload - testy wydajnościowe w Pythonie
Ponadto o przetwarzaniu obrazów, programowaniu w Qt 4.5 oraz... o tworzeniu aplikacji internetowych w Django autorstwa mojej skromnej osoby.

Oprócz o podstawach tworzenia projektu w tym frameworku piszę trochę o wbudowanym mechanizmie uwierzytelniania i autoryzacji. Cały numer można zakupić lub... ściągnąć za darmo* ze strony magazynu SDJ :)


A teraz troszkę muzyki... Utwór Django Reinhardt'a w wykonaniu Latches:



* - w cenie podania swojego adresu e-mail ;-P

wtorek, 16 lutego 2010

Mythbusters: Java jest wolna?

Jeszcze raz usłyszę w dyskusji o wyższości jednego języka programowania nad drugim od jakiegoś domorosłego programisty, że Java ssie, bo jest masakrycznie wooolnaaa, to osobiście od siły argumentów przejdę do argumentów siły i wyklepię mu maskę. Owszem, Java ssie, ale z zupełnie innych powodów ;-) Ale o tym kiedy indziej, teraz oddaję głos ekspertom:


Adam: Hej, Jamie, słyszałeś ten popularny mit krążący wśród programistów, że Java jest wolna?

Jamie: Jasne, ciekawe, że opinię taką wygłaszają ludzie którzy najczęściej nigdy nie napisali w tym języku ani linijki kodu...

Adam: No ale przecież niż prostszego niż napisać kod w paru językach robiący to samo i sprawdzić który szybciej się wykona?

Jamie: Pewnie! To do roboty, ale wysadzimy coś przy okazji?


Bierzemy do porównania: Javę 1.6, Pythona 2.6, Ruby 1.9 (a co, 'podobno' duuużooo szybszy niż 1.8), JRuby 1.4 (no co ty? język skryptowy odpalany w maszynie wirtualnej Javy, to dopiero musi obsysać) i na dokładkę PHP 5.2...

To wszystko odpalimy na maszynie z systemem Ubuntu 9.10 64-bit. Parametry: AMD Athlon 64 X2 Dual Core 4200+, 2GB RAM.

Algorytmem testującym będzie algorytm rekurencyjny obliczający kolejne liczby ciągu Fibonacciego. Implementacja wynika wprost z definicji i nie jest to najszybszy algorytm na obliczanie kolejnych liczb tego ciągu (złożoność wykładnicza, istnieje szybszy - liniowy). Nie są to też najszybsze sposoby na zrobienie tego w danym języku, chodzi jednak o to, żeby w każdym z nich zrobić to w 'niemalże' ten sam sposób (na ile pozwala składnia danego języka) ;-).

PYTHON
def fib(n):
   if n == 0 or n == 1:
      return n
   else:
      return fib(n-1) + fib(n-2)

for i in range(36):
    print "%d => %d" % (i, fib(i))

RUBY
def fib(n)
  if n == 0 || n == 1
    n
  else
    fib(n-1) + fib(n-2)
  end
end

36.times do |i|
  puts "#{i} => #{fib(i)}"
end

JAVA
public class Fibonacci {

 public static long fib(int n) {
   if (n == 0 || n == 1) {
    return n;
   } else {
    return fib(n-1) + fib(n-2);
   }
 }

 public static void main(String[] args) {
    for (int i = 1; i < 36; i++) {
       System.out.println(i + " => " + fib(i));
    }
 }
}

PHP
function fib($n) {
 if ($n == 0 || $n == 1) {
  return $n;
 } else {
  return fib($n-1) + fib($n-2);
 }
}

for ($i = 1; $i < 36; $i++) {
 echo $i . ' => ' . fib($i) . "\n";
}

Każdy program odpalę 10 razy i wyciągnę średnią z wyniku. Czas wykonywania zmierzy komenda time.

A oto i uzyskane wyniki (w sekundach):

  • ruby 1.9.1p243 (2009-07-16 revision 24175) [x86_64-linux]
    17.672, 17.618, 17.615, 17.431, 17.400, 17.409, 17.414, 17.442, 17.498, 17.689
  • Python 2.6.4:
    28.776, 28.352, 28.467, 28.268, 28.650, 28.307, 28.768, 28.987, 28.863, 28.278
  • jruby 1.4.0 (ruby 1.8.7 patchlevel 174) (2009-11-02 69fbfa3) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_15) [amd64-java]
    11.434, 10.885, 11.637, 12.217, 10.686, 11.372, 12.055, 10.704, 11.667, 11.118
  • Java(TM) SE Runtime Environment (build 1.6.0_15-b03) Java HotSpot(TM) 64-Bit Server VM (build 14.1-b02, mixed mode)
    0.522, 0.452, 0.442, 0.423, 0.424, 0.423, 0.419, 0.451, 0.446, 0.427
    + czas kompilacji: ~1.2 sek. (jednorazowo)

    ...i na koniec:
  • PHP 5.2.10-2ubuntu6.4 with Suhosin-Patch 0.9.7 (cli) (built: Jan 6 2010 22:56:44)
    51.864, 52.694, 53.285, 52.890, 52.774, 52.198, 52.209, 52.901, 52.517, 52.174

    Już widać co i jak, ale jeszcze oficjalna tablica wyników:

    1. Java 1.6 - 0.443 sek.
    2. JRuby 1.4 - 11.377 sek.
    3. Ruby 1.9.1 - 17.519 sek.
    4. Python 2.6.4 - 28.572 sek.
    5. PHP 5.2.10 - 52,551 sek.

    Tak więc program w Javie wykonał się ponad 100 razy szybciej niż w PHP! Trochę mnie zdziwił Python, miałem nadzieję na wynik w okolicach Rubiego. JRuby okazał się szybszy od swojego brata.

    A co z mitem?


    P.S. Jak pisałem wcześniej, nie są to najszybsze możliwe algorytmy dla tego zadania. Jaki Ty znasz sposób na jak najwydajniejszy algorytm obliczania ciągu Fibonacciego w swoim ulubionym języku?
  • wtorek, 9 lutego 2010

    Rails 3.0 + Ruby 1.9 na Ubuntu 9.10

    5 lutego ukazała się wersja 3.0 beta środowiska Rails. Pełna notka o wydaniu tu. Wersja ta jest długo oczekiwanym efektem połączenia sił (i kodu) ludzi pracujących nad Rails i Merb. Pierwsze pogłoski o merge'u pojawiały się około grudnia 2008, dziś efekt tych prac biorę sobie na warsztat :)

    Instalacja w Ubuntu 9.10

    Instalacja w wersji dla leniwych. W systemie zainstalowany zostanie Ruby w wersji 1.9.1 oraz Gems 1.3.5.
    $ sudo apt-get install ruby1.9.1-full rubygems1.9.1

    jeśli nie mieliśmy wcześniej innych wersji rubiego, podlinkujmy:
    $ sudo ln -s /usr/bin/ruby1.9.1 /usr/bin/ruby

    Jeśli mieliśmy, zmieńmy ten symlink tak aby wskazywał na najnowszą wersję.

    Teraz sprawdźmy co gdzie jest:
    $ gem environment

    powinniśmy otrzymać coś w tym stylu:
    RubyGems Environment:
      - RUBYGEMS VERSION: 1.3.5
      - RUBY VERSION: 1.9.1 (2009-07-16 patchlevel 243) [x86_64-linux]
      - INSTALLATION DIRECTORY: /var/lib/gems/1.9.1
      - RUBY EXECUTABLE: /usr/bin/ruby1.9.1
      - EXECUTABLE DIRECTORY: /var/lib/gems/1.9.1/bin
      - RUBYGEMS PLATFORMS:
        - ruby
        - x86_64-linux
      - GEM PATHS:
         - /var/lib/gems/1.9.1
         - /home/jasio/.gem/ruby/1.9.1
      - GEM CONFIGURATION:
         - :update_sources => true
         - :verbose => true
         - :benchmark => false
         - :backtrace => false
         - :bulk_threshold => 1000
      - REMOTE SOURCES:
         - http://gems.rubyforge.org/

    Teraz do pliku .bashrc dodajmy na koniec lokalizację naszych gemsów:
    $ gedit ~/.bashrc

    w ostatniej linii dopisujemy:
    export GEM_HOME="/var/lib/gems/1.9.1"

    Pamiętajmy że zmienna zaistnieje w środowisku po otwarciu nowej konsoli. Ewentualnie wykonajmy powyższe polecenie z palca.

    OK. Teraz czas na instalację Railsów i potrzebnych zależności:
    $ sudo gem install tzinfo builder i18n memcache-client rack rake rack-test rack-mount erubis mail text-format thor bundler
    $ sudo gem install rails --pre

    Podlinkujmy railsy w /usr/bin:
    $ sudo ln -l /var/lib/gems/1.9.1/bin/rails -v /usr/bin/rails

    Na koniec przydałaby się jakiś przynajmniej sqlite:

    $ sudo apt-get install sqlite3 libsqlite3-dev
    $ sudo gem install sqlite3-ruby

    Hello World!

    OK. Teraz generujemy zalążek aplikacji:

    $ rails myapp
    $ cd myapp
    $ rails server

    ... i działa :)

    piątek, 3 kwietnia 2009

    Generator liczb pseudolosowych (cz.3) - rozkład Cauchy'ego

    Witajcie, zgodnie z obietnicą, w tym odcinku generujemy liczby losowe z rozkładu Cauchy'ego.

    Jak w poprzednim odcinku, użyjemy generatora rozkładu równomiernego. Kod metody getFromCauchyDistribution() wygląda następująco:
    double RandomNumberGenerator::getFromCauchyDistribution() {

    // generuj X o rozkładzie równomiernym U(-1,1)
    double X = getFromUniformDistribution() * 2 - 1;

    // generuj X o rozkładzie równomiernym U(0,1)
    double U = getFromUniformDistribution();

    if ((U + 0.27324) * (1 + X * X) > 1.27324) {
    X = getFromUniformDistribution() * 2 - 1;
    }

    // uzupelnienie rozkładu o "ramiona"
    if (getFromUniformDistribution() > 0.5) {
    return X;
    } else {
    if (X != 0) {
    return (1 / X);
    } else {
    return MAXDOUBLE;
    }
    }
    }
    Możemy przerobić nieco program z poprzedniego odcinka generujący dane statystyczne potrzebne do narysowania histogramu. Otrzymane wyniki porównamy z tymi, które dostarczył nam generator rozkładu normalnego.



    Jak nietrudno się domyślić, ten pomarańczowy wykres to histogram dla liczb z rozkładu normalnego a niebieski - z Cauchy'ego.

    środa, 1 kwietnia 2009

    Generator liczb pseudolosowych (cz.2) - rozkład normalny

    W poprzednim odcinku otrzymaliśmy całkiem przyzwoity generator liczb o rozkładzie równomiernym. Teraz uzupełnimy naszą klasę o metodę do pobierania wartości z rozkładu normalnego, zwanego też rozkładem Gaussa.

    Zastosowanym algorytmem do generowania liczb losowych z rozkładu normalnego jest implementacja metody Kindermana i Monahana, zwanej ROU (ratio-of-uniforms method). Szczegóły tej metody można znaleźć w książce Wieczorkowskiego i Zielińskiego[2]

    Moja implementacja w języku C++ zawarta jest w metodzie getFromNormalDistribution() klasy RandomNumberGenerator i wygląda następująco:

    double RandomNumberGenerator::getFromNormalDistribution(){
    bool ok = false;
    double limit = sqrt(2/2.718281828);
    double X;

    do {
    // generuj U o rozkładzie równomiernym U(0,1)
    double U = getFromUniformDistribution();
    // generuj V o rozkładzie równomiernym
    // U(-sqrt(2/e),sqrt(2/e))
    double V = 2 * limit * getFromUniformDistribution() - limit;
    X = V / U;

    if (X*X <= 2*(3-U*(4+U))) {
    ok = true;
    } else if (X*X <= 2/U - 2*U) {
    if (X*X <= -4*log(U)) {
    ok = true;
    }
    }
    } while (!ok);
    return X;
    }
    Jak widać używa on metody getFromUniformDistribution() zdefiniowanej wcześniej a zwracającej nam dwie liczby z rozkładu rónomiernego, jedna z przedziału (0,1) a druga z (-sqrt(2/e), sqrt(2/e)).

    Ok. Teraz wypadałoby jakoś przetestować nasz generator. Do tego celu napiszemy szybko programik generujący histogram otrzymywanych wartości. Oto on:
    #include <iostream>
    #include <vector>
    #include <math.h>
    #include "source/RandomNumberGenerator.cpp"

    using namespace std;

    int main(int argc, char* args[]) {

    // wektor przechowywujący liczebność wylosowanych liczb w danym przedziale
    vector<double> histogram;

    double min = -3; // dolna granica
    double max = 3; // górna granica
    double n = 1000; // liczba przedziałów

    // krok o jaki będą zwiększać się kolejne przedziały
    double step = (max - min) / n;

    // zainicjowanie licznikow
    for (int i=0; i < n; i++){
    histogram.push_back(0);
    }

    // losowanie i określenie w którym przedziale znajduje się wylosowana liczba
    for (int k=0; k<10000000; k++) {

    // pobranie wartości losowej
    double X = RandomNumberGenerator::Instance()->getFromUniformDistribution();

    // 'odległość' od dolnej granicy
    double lX = X - min;

    if ((X >= min) && (X <= max)){
    int i = (int) floor(lX / step); // obliczenie, do którego przedziału zalicza się wylosowana wartość
    histogram[i] = histogram[i] + 1; // zwiększenie licznika danego przedziału
    }
    }

    // wyprowadzenie wartości liczników na standardowe wyjście
    for (unsigned int j=0; j < histogram.size(); j++){
    cout << histogram[j] << endl;
    }
    return EXIT_SUCCESS;
    }
    Przekierowując dane ze standardowego wyjścia na plik, można zapisać otrzymane wyniki:
    $ ./RandomGen > stats.txt

    Teraz statystyki można wsadzić np. do OpenOffice'a i wygenerować histogramy:


    Histogram otrzymany dla 10 tys. liczb


    Histogram dla 100 tys. liczb

    I co, fajnie? :) To teraz zwiększmy liczbę kroków pętli for do... 10 milionów:


    Całkiem ładny rozkład normalny? To tyle na razie... w następnym odcinku zajmiemy się rozkładem Cauchy'ego...