Pokazywanie postów oznaczonych etykietą Python. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą Python. Pokaż wszystkie posty

piątek, 7 maja 2010

Ajax w Django. Dajax Project w akcji

Natchnęło mnie kiedyś (już nawet dość dawno) żeby przetestować bibliotekę Dajax do Ajaxa w Django.
Napisałem prostą aplikacyjkę w stylu guestbook.

Potrzebowałem oczywiście dajaxa, którego można sciągnąć ze strony: http://www.dajaxproject.com/
Dajax współpracuje z kilkoma frameworkami JavaScriptowymi, mianowice: jQuery, Prototype, MooTool i Dojo.

No to do dzieła: w settings.py dodajemy wpisy:
DAJAX_JS_FRAMEWORK = "prototype"
DAJAX_MEDIA_PREFIX = "dajax" # http://domain.com/dajax/
DAJAX_CACHE_CONTROL = 10 * 24 * 60 * 60
DAJAX_FUNCTIONS = (
    #Ajax funtions registered to examples.ajax
    'guestbookapp.ajax.pagination',
    'guestbookapp.ajax.send_form',
)

ENTRIES_ON_PAGE = 2
Będę korzystał z prototype, dodatkowo zarejestrowałem dwie funkcje:
send_form - do dodawania nowego wpisu do mojego guestbook'a i pagination do stronicowania wpisów ... ale o nich później.

Teraz ważny trick w urls.py musimy w dodać wpis:
urlpatterns += patterns('',
    ...
    # dajax handler
    (r'^%s/' % settings.DAJAX_MEDIA_PREFIX, include('dajax.urls')),
    ...

To tyle w konfiguracji samego środowiska django. Teraz możemy przejść do tworzenia samej aplikacji, nazwijmy ją guestbook.

plik models.py, chyba niczym tu nie zaskocze - jedna klasa:
from django.db import models

class Entry(models.Model):
    author = models.CharField(u'author', max_length=50)
    email = models.EmailField(blank=True, max_length=50)
    content = models.TextField(u'greeting')
    pub_date = models.DateTimeField(u'added at', db_index=True, auto_now_add=True)
    
    class Meta:
        verbose_name = 'Entry'
        verbose_name_plural = 'Entries'
        ordering = ('-pub_date',)

    def __unicode__(self):
        return self.author

Nie muszę chyba opisywać co zawiera wpis w księdze gości ;)

W zasadzie będziemy mieli tylko jedną stronę, wszystkie requesty będą kierowane przez ajaxa.

Zawartość pliku views.py:
from guestbook.utils import render_response
from django.conf import settings
from django.views.generic import list_detail
from models import Entry
from forms import EntryForm 

def get_pagination_page(page=1):
    from django.core.paginator import Paginator, InvalidPage, EmptyPage
    from django.template.loader import render_to_string
    paginator = Paginator(Entry.objects.all(), 2)
    try:
        page = int(page)
    except ValueError:
        page = 1
    try:
        items = paginator.page(page)
    except (EmptyPage, InvalidPage):
        items = paginator.page(paginator.num_pages)
    return items

def start(request):
    items = get_pagination_page(1)
    context = {
        "form" : EntryForm(),
        "items" : items,
    }
    return render_response(request,'guestbookapp/entry_list.html', context)

Widok start to jedyna strona startowa z formularzem i listą wpisów.

I czas opisać opisać zarejestrowane funkcje (ajax.py):
from django.conf import settings
from dajax.core import Dajax
from models import Entry 

def pagination(request):
    from guestbook.guestbookapp.views import get_pagination_page
    from django.template.loader import render_to_string
    from django.core.paginator import Paginator, InvalidPage, EmptyPage
    try:
        page = int( request.POST['p'] )
    except:
        page = 1
    paginator = Paginator(Entry.objects.all(), settings.ENTRIES_ON_PAGE)
    try:
        items = paginator.page(page)
    except (EmptyPage, InvalidPage):
        items = paginator.page(paginator.num_pages)
    render = render_to_string('guestbookapp/pagination_page.html', { 'items': items })
    dajax = Dajax()
    dajax.assign('#pagination','innerHTML',render)
    return dajax 
 
Paginacja, w zmiennej settings.ENTRIES_ON_PAGE przechowuje liczbę wpisów na stronie

def send_form(request):
    from dajax.utils import deserialize_form
    from forms import EntryForm

    dajax = Dajax()
    form_data = deserialize_form( request.POST.get('form') )
    form = EntryForm(form_data)
    print form
    if form.is_valid():
        from django.core.paginator import Paginator, InvalidPage, EmptyPage
        from django.template.loader import render_to_string
        form.save()
        dajax.removeCSSClass('#add_entry_form input','error')
        form.save()
        #dajax.alert("This form is_valid(), your mail is: %s" % form.cleaned_data.get('email'))
        paginator = Paginator(Entry.objects.all(), settings.ENTRIES_ON_PAGE)
        try:
            items = paginator.page(1)
        except (EmptyPage, InvalidPage):
            items = paginator.page(paginator.num_pages)
        render = render_to_string('guestbookapp/pagination_page.html', { 'items': items })
                
        dajax = Dajax()
        dajax.assign('#pagination','innerHTML',render)
        dajax.assign('#add_form', 'innerHTML', '')
    else:
        dajax.removeCSSClass('#add_entry_form input','error')
        for error in form.errors:
            dajax.addCSSClass('#id_%s' % error,'error')
    return dajax
Wysyłanie formularza ajaxem, w rosponse'ie otrzymujemy informacje o błędach, które są potem podmieniane w widoku.
Zauważcie, że nie musimy bawić się z serializację np. JSONem, wszystko zrobią za nas metody zawarte w dajax.utils odpowiedzialne na przykład za de-serializację formularzy.

Jak to wygląda w akcji?

To tyle, miłej zabawy ajaxem.

sobota, 13 lutego 2010

Python IDE który wspiera Django :)

Niedawno natknąłem się na bardzo ciekawe IDE dla Pythona, wsparcie dla Django to jedna z jego zalet.


Możliwości: http://code.google.com/p/pyscripter/wiki/Features

piątek, 25 grudnia 2009

Wesołych Świąt

Z okazji świąt przygotowałem ciekawy skrypcik:
                 *                  
                ooo                 
               %oo%*                
              %%*oo*%               
             **ooo%oo*              
            **%%%*o%%o%             
                 %                  
                *%o                 
               %*%%%                
              **oo*o%               
             %%*o*o*%*              
            **%%*o**o%%             
           **o*o%o*%**%*            
          %%*o%%*%***%***           
         %%oo**%**oo%ooo*%          
        *%*%*%*%*oo%*%**%**         
       %ooooo*%%*o*oo*%*%*%%        
      *%oo**o*oo%oo%**ooo%%%%       
                 *                  
                ***                 
               o%o*o                
              %*%oo%*               
             o%*o*%**%              
            %***%oo%o*%             
           *o%o%%%%%%*%*            
          **%*o%%**o*%***           
         %*ooo%o%%o*%%**%%          
        *%%o%o***o%*%%%**o*         
       *****oo*oo*%%%**%%%o%        
      %***o%%**%%%o*oooo%***%       
     %o**o*o%***%%%o%o**%oooo*      
    o%o*o**oo*o%o**o%%%%%o%%**o     
   o*o%o%*%oo%*oo%%o*ooooo%**oo*    
  o*oo*o%%o*ooo%****oo*o%%o%o%*%%   
 *oo*ooo%o**o%**oo*o%%%o%o%oo%o*oo  
o**%ooo%o*o*o*%%o%*%%o%o%%o*oo%**** 

           Wesołych Świąt    


#!/usr/local/bin/python
# -*- coding: utf-8 -*-
import random

def ChristmasTree(levels, n, decoration=["*"]):
    """
    level - liczba poziomów drzewka
    n - wysokość pierwszego poziomu
    decoration - lista ozdób drzewka 
    """
    for j in range(1,levels+1):
        for i in range(j*n):
            line = ""
            for k in range(2*i+1):
                line +=  random.choice(decoration)
            print line.center(2*levels*n)
    print ""
    print u'Wesołych Świąt'.center(2*levels*n) 

ChristmasTree(3, 6, ["*","%","o"])

PS. potrafisz uzyskać podobny efekt w innym języku programowania?
Podejmij wyzwanie :)

piątek, 10 lipca 2009

Potrzebujesz małe forum ?

...dodatkowo z darmowym hostingiem...bez reklam...w domenie appspot.com

Właśnie napisałem malutkie forum w GAE bazujące na stylu phpBB.

jak to wygląda? tutaj jest przykład: small-forum

Stąd można pobrać najnowszą wersje: small forum na google code

Jak zainstalować?

znaleść w pliku main.py linijkę:


class AclUser:
__admin__ = 'Twój google login' #(login administratora)

w pliku app.yaml:
application: small-forum #zmienić na własną nazwę aplikacji
i wgrać forum:
$python appcfg.py update forum

piątek, 24 kwietnia 2009

Google App Engine :: Klasa User

Google App Engine sprytnie rozwiązuje kwestie użytkowników, także przy tworzeniu aplikacji możemy łatwo wykorzystać klasę user z google api ( from google.appengine.api import users). Wystarczy, że użytkownik posiada konto w google, a my w łatwy sposób możemy 'wyciągnąć': nickname, user_id oraz jego adres mailowy.
Służą do tego metody - odpowiednio:
  1. nickname()
  2. user_id()
  3. email()
Co więcej dla naszego użytkownika przewidziany jest odpowiedni typ w bazie danych
- db.UserProperty()

A teraz zakładamy scenariusz: jak użytkownik nie jest zalogowany to przekierowywujemy go na stronę logowania, a jak jest zalogowany to wyświetlamy jego nickname oraz dajemy możliwość wylogowania się.


user = users.get_current_user()
if user:
self.response.out.write(user.nickname() + """ |
<a href="users.create_logout_url(self.request.uri)" >
Sign out</a>""")
else:
self.redirect(users.create_login_url(self.request.uri))


jeszcze możemy sprawdzić czy użytkownik ma uprawnienia administratora:
is_current_user_admin() - zwraca True jeśli tak.

Źródło (więcej na): http://code.google.com/appengine/docs/python/gettingstarted/

czwartek, 23 kwietnia 2009

Google App Engine - test możliwości

Google App Engine to świetne narzędzie do tworzenie dynamicznych stron oraz aplikacji webowych.
Ale to nie wszystko, bo to również darmowy hosting tych aplikacji + baza danych i wiele innych pożytecznych funkcji włącznie z panelem administracyjnym.

Co o bazie danych i języku Gql?

Niby obiektowe, ale z możliwością zadawania zapytań w języku gql - googlowa wersja sql'a :)
Co więcej zapytanie do bazy zwraca kolekcję obiektów.

Wpis w bazie jest obiektem stworzonej przez nas klasy, po kontakcie z ZODB czy Gadfly nie powinno to już nikogo dziwić.

Prosty przykład:

class BazaObiektow(db.Model):
author = db.UserProperty()
title
= db.StringProperty()
body
= db.TextProperty()

obiekty = db.GqlQuery("SELECT * FROM BazaObiektow")
# oczywiście można dodać jeszcze WHERE :)
# GqlQuery Class
for obiekt in obiekty:
#iterujemy po obiektach
self.response.out.write(str(obiekt.author) + '...wypisujemy co chcemy')


A jak się pisze kontroler i widok:

też fajnie, jest nawet system template'ów, co do google.appengine.api i cgi jest, jak narazie, troche słabo udokumentowane - trzeba się dużo naszukać, żeby znaleść informacje jak na przykład zapisać ciastka. Chociaż można się tego domyśleć :)

Dla zabawy napisałem prostą aplikacyjke do operacji na obrazach: zmiana wielkości( resize), obracanie o kąt( wielokrotność 90 stopni), odbicie symetryczne i poprawa kontrastu - a wszystko w oparciu o google.appengine.api - klasa images.

Można testować tutaj: My Images

aha, aplikacja jest po angielsku, ale łatwo się pokumać jakie funkcje do czego służą.

No i to by było na tyle...

Podsumowując - google app engine wywiera pozytywne wrażenia :)

czwartek, 5 lutego 2009

Dlaczego Python? - czyli "programowanie z klocków" :)

Dlaczego w Pythonie pisze się tak łatwo szybko i przyjemnie?

Jedną z zalet Pythona jest super prosta składnia, która pozwala pisać bardzo zwięzły kod. Pamiętam taki argument: dlaczego znaki {, } w C są lepsze niż begin i end Pascala? - bo pozawalają każdorazowo zaoszczędzić 6 znaków :) Idąc tą drogą można napisać, że Python jest lepszy na przykład od Javy, bo oszczędza jeszcze te 2 znaki :)

Wymuszanie wcięć w kodzie skutkuje dobrymi nawykami - dotyczy to przede wszystkim początkujących programistów. Ale ma też swoje wady: trudniej jest przenieść fragment kodu na przykład do innej klasy, a zmiana głębokości wcięcia zazwyczaj zmienia działanie fragmentu kodu.
Python jest w pełni obiektowy, ale nic nie stoi na przeszkodzie, żeby pisać w nim strukturalnie - co kto lubi. A znam takie języki w których można pisać tylko i wyłącznie obiektowo ( żeby wypisać 'Hello World' na ekran trzeba napisać klasę, lol).

Spotkałem się z argumentem, że Python jest wolny. Jak na język skryptowy nie jest wcale taki wolny, choć porównywanie jego szybkości z C++ nie ma raczej sensu.

Przede wszystkim pisanie programów w Pythonie przypomina budowanie go z klocków - gotowych komponentów. Biblioteki tego języka w większości napisane są w czystym C dzięki czemu musi on być szybki.
Jak wiadomo, jest to język skryptowy tak jak Perl, PHP, Ruby czy wiele innych, wirtualna maszyna potrafi skonwertować sobie skrypcik do bytecode'u, a wszysto po to żeby działał czybciej.

Jednym z argumentów przemawiających za tym żeby uczyć/nauczyć się pythona jest fakt, że używa go Google( tylko mi nie mówcie: " ja używam Yahoo albo wyszukiwarki onetu" :) ) i NASA.

Każdy język programowania ma swoje zastosowanie, jednakże pole potencjalnego wykorzystania Pythona jest ogromne: począwszy od aplikacji webowych, a skończywszy na obliczeniach( w Pythonie nie ma zakresu liczb!!!, jedynym ograniczeniem jest fizyczna wielkość zasobów Twojego komputera). No może z wyjątkiem gier..., chociaż jest w końcu Pygame, VPython czy Ogre... :)

Ponadto łatwa konwersja typów, listy i kroki, a wszystko po to by ułatwić życie programiści.

Zresztą w sieci pojawia się wiele porównać typu C++ vs Java vs Python, w których nie wiedzieć czemu ;) Python zawsze wygrywa.

wtorek, 3 lutego 2009

Python i PicasaAPI: czyli znowu zdjęcia:)

Treści tutaj zawarte mają na celu pokazanie możliwości języka Python

Problem:


Jan Kowalski ( zbieżność nazwisk przypadkowa) ma konto Google, korzysta też z Picasy, ma kilka albumów, a w nich swoje zdjęcia.

Załóżmy, że chcemy je wszystkie sobie pobrać odtwarzając strukturę katalogów czyli na przykład:

jas.kowalski@gmail.com
|
| ---->wakacje2008 -> [zdjęcia]
|
|---->impreza urodzinowa -> [zdjęcia]
|
|---->wakacje2009 -> [zdjęcia]

itd.

Rozwiązanie:

Z pomocą jak zwykle przychodzi Python i w tym przypadku PicasaApi.

Oto przykład rozwiązania:

skrypt

skrypt.py

Będziemy też potrzebowali biblioteki gdata-python-client:

http://code.google.com/p/gdata-python-client/downloads/list

w sumie nie potrzebujemy wszystkich bibliotek, wystarczą 3:
gdata.photos.service.py
gdata.media.py
gdata.geo.py

a najprościej spkopiować cały katalog gdata do katalogu głównego skryptu.

enjoy

Ściąganie wszystkich zdjęć wybranego użytkownika z portalu Nasza-Klasa - wersja 3

UWAGA: Sktypt ma wyłącznie na celu pokazanie możliwości języka Python i jego bibliotek. Autor nie ponosi żadnej odpowiedzialności za działania skryptu oraz ewentualne straty nim spowodowane, pamiętaj korzystasz z niego na własną odpowiedzialność. Przed skorzystaniem upewnij się, że jego działanie jest zgodne z regulaminem serwisu Nasza-Klasa.

Udostępniam najnowszą i najbardziej dopracowaną wersję skryptu, w której nie trzeba podawać parametru max, ponieważ sprawdzam id ostatniego zdjęcia. To praktycznie wystarcza, bo jeśli użytkownik usunie jakieś zdjęcie pomiędzy to po prostu nie zostanie ono poprane( 404).

skrypt.py

potrzebna biblioteka httplib2:

httplib2


A więc ostateczna lista parametrów:
naszLogin naszeHasło Id

PS.
Proszę nie męczcie mnie już pytaniami jak zainstalować pythona czy jakieś biblioteki, albo dlaczego skrypt nie działa.

niedziela, 1 lutego 2009

Nasza-Klasa: pobieranie zdjęć - poprawiona wersja

UWAGA: Sktypt ma wyłącznie na celu pokazanie możliwości języka Python i jego bibliotek. Autor nie ponosi żadnej odpowiedzialności za działania skryptu oraz straty nim spowodowane, pamiętaj korzystasz z niego na własną odpowiedzialność. Przed skorzystaniem upewnij się, że jego działanie jest zgodne z regulaminem serwisu Nasza-Klasa.

Nawiązując do mojego wcześniejszego posta , po drobnym researchu wyciągnełem kilka wniosków, które zaowocowały drugą wersją sktyptu.

Po pierwsze nie musimy się już przejmować ciastkami( cookies) za to lista parametrów programu wydłużyła się o 2 i teraz wygląda tak:

nasza-klasa.py TwójLoginDoNK TwojeHasło IdOsobyKtórejZdjeciaChcemyPobrać MaxZdjeć

przy czym czwarty parametr jest opcjonalny i jeżeli nie wpiszemy nic - to przyjmie domyślną wartość - 50.

Po Drugie: jak zauważyłem RSS zwraca tylko 10 ostatnich zdjęć ( da sie pobrać RSSa dla wszystkich zdjęć?) , wiec ten pomysł na razie odpada.

zobacz kod: kod
pobierz: nasza-klasa.py

enjoy.

Ściąganie wszystkich zdjęć wybranego użytkownika z portalu Nasza-Klasa

UWAGA: Sktypt ma wyłącznie na celu pokazanie możliwości języka Python i jego bibliotek. Autor nie ponosi żadnej odpowiedzialności za działania skryptu oraz straty nim spowodowane, pamiętaj korzystasz z niego na własną odpowiedzialność. Przed skorzystaniem upewnij się, że jego działanie jest zgodne z regulaminem serwisu Nasza-Klasa.

Napisałem prosty skrypcik do sciągania n pierwszych zdjęć użytkownika o znanym Id na Naszej-Kasie. Już tłumaczę jak on działa i co porzebujemy:

1) musimy mieć konto w serwisie Nasza-Klasa
2) musimy znać id użytkownika, którego zdjęcia chcemy pobrać: można je łatwo znaleść na przykład w pasku adresu url( http://nasza-klasa.pl/profile/xxxxxxx, gdzie xxxxxxx to właśnie to Id)
3) ponieważ mój sktypt jest troche prymitywny:) i nie sprawdza ilośći zdjęć naszego użytkownika musimy podać ile zdjęć chcemy ściągnąć - ale tu można podać spokojnue większą liczbe, bo skrypt jest odporny na błędny
4) i wreszcie najważniejsze: musimy mieć zainstalowanego pythona i parę bibliotek( przypuszczam że wszyskie są w katalogu lib Pythona)
5) WAŻNE: musimy pobrać cookie zalogowanego użytkowika, bo jak na razie skrypt tego nie robi, i wpisać je do zmiennej:

cookies = 'remember_me=...; __utma=...; cookies += ' nk_session=...'

polecam Live HTTP Header do tego celu, można je znaleść też w przeglądarce( Firefox2: Narzędzia->Opcje->Wyświetl Ciasteczka->'wpisujemy w filtrze: nasza-klasa'->i odczytujemy poszczególne ciastka)

jak uruchamiać?:

Linux:
$ python nasza-klasa.py Id max (np. $ python nasza-klasa.py 1234567 50)
Windows:
start->cmd i wpisujemy: nasza-klasa.py Id max

no i źródła:

nasza-klasa.py

miłej zabawy, pozdro

TO DO:
* ułatwić podawanie cookies
* oprzeć silnik na RSS/XML

niedziela, 26 października 2008

Bot gadu-gadu z wykorzystaniem EKG i Python'a

Opiszę jak w prosty sposób napisać własnego bot'a gg.
Wymagana jest podstawowa znajomość języka Python i środowiska Linux.

Użytkownicy [x/k]Ubuntu mogą pobrać EKG z repozytorium wpisując:
sudo apt-get install ekg
warto też zainstalowa najnowszą wersje Pythona
sudo apt-get install python
pozstali muszą skompilować ze źródeł.
A teraz do dzieła:

odpalamy ekg: #ekg

wpisujemy
set uin 'numer gg'
set password 'hasło'
save

teraz czas zacząc pisać bota:
przechodzimy do katalogu ~/.gg/
tworzymy katalog scripts (#mkdir scripts)

i tu tworzymy plik najlepiej z rozszerzeniem .py

jeśli chcemy by nasz skrypcik odpalał sie zaraz po uruchomieniu EKG w katalogu scripts tworzymy kolejny katalog: autorun i tu wrzycamy nasz plik.
stuktura programu:

# importujemy bibliotekę ekg
import ekg

#ta funkcja wywołuje się przy starcie skryptu
def init():
ekg.printf("generic","Bot loaded");
#ustawiamy opis
ekg.command("_descr \"Opis\"");
return 1

#ta funkcja wywołuje się przy zamykaniu skrypu
def deinit():
ekg.printf("genetic","Bot unloaded");
logfile.close()

#przechwytywanie zdarzeń:
def handle_msg(uin, name, msgclass, text, time, secure):

uin - numer gg od którego przyszła wiadomość
text - treść wiadomości
time - czas nadejscia

pozostałe parametry są raczej mniej istotne.

Zabawa polega na tym, aby przechwycić text i odpowiednio na niego odpowiedzieć.

Jak narazie napisałem prosty kalkulator.



Ale zamierzam napisać coś znacznie ciekawszego:)

I jeszcze wywołanie skryptu: w konsolce ekg:
python (un)load nazwa_skryptu.py

czwartek, 24 lipca 2008

Python, biblioteka urllib(2) i dodatkowe aspekty bezpieczeństwa aplikacji webowych

urllib (2) jest biblioteką Pythona do pobierania plików poprzez adres url,
dodatkowo umożliwia manipulację całego zapytania, pozwala na tworzenie własnego nagłówka zapytania cz manipulację ciasteczek, a nawet wysyłanie POST content'u.

Przyjrzyjmy sie prostej funkcji:

zobacz

zmienne user_agent i user_agent2 zawierają zmienną naszego agenta czyli tak jak zazwyczaj przedstawia się przeglądarka internetowa.

Za zmienną user_agent możemy podstawić dowolnego stringa w tym taki xml'owe (html'owe) a nawet kod dowolnego języka najlepiej skryptowego.

Jeżeli nieuważny webmaster posiada na swoim serwerze system do przeglądania statystyk, który wyświetla wszystkie informacje o użytkownikach, którzy przeglądali strony może nieświadomie uruchomić JavaScript, który podrzucimy mu w zmiennej user_agent. Oczywiście ten alert() w przykładzie jest bardzo subtelny, równie dobrze można by tam dorzucić jakiś XSS.



kolejna zmienna zawiera ciasteczka w naszym przypadku PHPSESSID.
Różna może być reakcja skryptu na serwerze w przypadku, gdy zmienna sesji posiada niedozwolone znaki. Polecam to sprawdzić.

funkcja save_it(url, filename, proxy, port) zapisuje zawartość strony zawartej pod adresem url do pliku filename, a jeśli zmienna proxy jest różna od None to połączenie odbywa się przez serwer proxy na podanym porcie.

Na koniec dorzucam jeszcze skrypt do wysyłania POST contentu:

zobacz