28 Aralık 2008 Pazar

Python 3.0'da Söz Dizimi Değişiklikleri: Öznitelik İçin Açıklamalar (Attribute Annotations)

(Arkadaşlar merhaba. Bugün Özgür Sönmez arkadaşımız eposta yoluyla, Python 3.0'daki söz dizimi değişiklikleriyle ilgili nefis bir yazı, hatta sitemizin ismine uygun bir şekilde tabiri caizse nefis bir deneyim paylaşımında bulundu, ben de aynı şekilde buraya aktarıyorum. Sorularınız için yorumlarınızı bekleriz.)

Python 3000'de birçok değişiklik var; bunlardan biri de sözdizimindeki değişiklikler. Bugün burada özniteliklere açıklama eklemenin python 3000'de ne kadar kolay ve göze hitap eden bir biçimde yapılabildiğini göreceğiz. Öyle ki, açıklamalar artık string (katar) olmak zorunda bile değil:


def Toplam (x: "Toplanacak Birinci Sayı", y: "Toplanacak İkinci Sayı") -> "Toplamın Sonucu":
...


ifadesi;

def Toplam (x,y):
...


ifadesi ile fonksiyonel olarak aynı. Ancak python içinde bir kodda bu metodun __annotation__ özniteliğini kullanırsanız şu şekilde bir sözlük alırsınız:


{'x': 'Toplanacak Birinci Sayı'
'y': 'Toplanacak İkinci Sayı'
'return': 'Toplamın Sonucu'
}


python.org'da söylendiğine göre bu yenilik bir framework ya da metaclass deneyimini cesaretlendirmek için getirilmiş bir açıklama standardizasyonu. Örnekte de gördüğümüz gibi bu yenilik gerçekten göz kamaştırıcı. Öyle ki, py'ciler bununla kalmamışlar, örneğin:


def StoktanGetir(malzeme: "Getirilecek malzemenin adı", no: "Getirilecek malzemenin no'su" = 1):
...


ifadesinde olduğu gibi. Açıklamaları eklerken varsayılan parametreden de vazgeçilmemiş. Üstelik en önemlisi açıklamalar fonksiyon parantezlerinin içinde yer alıyor. Bir başka belirtmek istediğim şey de açıklamaların katar olma zorunluluğunun olmaması. Bir sözlük yapısında olduğu için __annotations__ içinde değer olarak giren açıklamalar her türden olabilir.
Anlaşılıyor ki bundan böyle fonsiyonlarımızı şöyle yazacağız:


def aligel(x: "Nereye (string)",
y: "Kentkartım doluysa true, değilse false (bool)") -> "Gelebilecekse true, gelemeyecekse false":


İyi Çalışmalar.

10 Aralık 2008 Çarşamba

PyGame hakkında

Pygame, Python kullanıcıları rahatça oyun geliştirebilsin diye Pete Shinners tarafından geliştirilmeye başlanmış bir Python pakedi. İçerisinde şu modüller ile birlikte geliyor :
  • Cdrom (manage cdrom devices and audio playback)
  • Cursors (load cursor images, includes standard cursors)
  • Display (control the display window or screen)
  • Draw (draw simple shapes onto a Surface)
  • Event (manage events and the event queue)
  • Font (create and render Truetype fonts)
  • Image (save and load images)
  • Joystick (manage joystick devices)
  • Key (manage the keyboard)
  • Mouse (manage the mouse)
  • Mask
  • Mixer
  • Movie (playback of movies)
  • Music (playback of music)
  • Overlay
  • Pixelarray
  • Rect
  • Sndarray
  • Sprite
  • Surface
  • Surfarray (manipulate images with Numeric)
  • Time (control timing)
  • Transform (scale, rotate, and flip images)
Görüldüğü üzere zenginlik konusunda karun kadar zengin PyGame. Avantajlarının biri de geliştirdiğiniz uygulamanın diğer işletim sistemlerine kolayca port edilebilmesi. Hatta işleme gerek kalmaksızın Mac sistemlerde direkt olarak çalışıyor.

Bu pakedi kullanarak geliştirdiğiniz ürünleri istediğiniz her hangi bir lisans ile yayınlayabiliyorsunuz (evet para kazanmak da mümkün). Gücünü SDL (Simple DirectMedia Layer) denen bir kütüphaneden alıyor. Bahsi geçen SDL, C ve Assembly dili kullanılarak yazılmış bolca optimizasyondan geçmiş, hız konusunda tartışmasız bir biçimde tatmin edici. Anlayacağınız PyGame'in duruşu pek şirin olsa da arkasında bir canavar yatıyor.

Aslına bakarsanız bir video kurgu programı yapmak için bile uygun gördüm kendisini, "oyun yapmak için kütüphane" tanımı biraz zayıf kalıyor kendisini anlatmaya.

Evet SDL kütüphanesi çok güçlü ama "Python dili oyun programlama yapmak için uygun mu?" sorusunu cevaplamak gerekiyor.

Python çok üst seviyeli bir dil, bir C kodundan yaklaşık 20 kat yavaş çalışıyor. Zaten bu programlama dilini tercih ederken pek performansına bakarak karar vermedik hiçbirimiz. Python dilinin asıl vurucu noktası bildiğiniz gibi kolay öğrenilir olması, ve size çok çabuk çözümler sunabilmesi. Python ve PyGame ile oyun yapmaya niyetlendiyseniz, bir "enemy-territory yapayım" şeklinde hayallere dalmanız sizi hayal kırıklığına uğratır. Yapabileceğiniz genelde hafif diye tabir edebileceğimiz oyunlar. Zaten genelde PyGame ile yapılmış oyunları incelediğinizde flash oyunu türevi ya da eski ATARI-C64 oyunlarının yeniden yapılmış halleri ile karşılaşıyoruz.

Bunların yanında PyGame hoş bir topluluğa sahip.İnsanları oyun geliştirilmesine teşvik etmek amacıyla "bir hafta içerisinde en güzel oyunu kim geliştirecek?" konseptine sahip bir yarışma düzenliyorlar adı da PyWeek. Siteye uğrayıp en azından o hafta yarışmaya katılmış oyunları oylamak bile yeterince eğlenceli bir aksiyon. Gerçekten güzel işler var ve tabi ki hepsinin kodları açık.

26 Kasım 2008 Çarşamba

Nano Snake

Cep telefonlarından bildiğimiz yılan oyunu Python ile 13 satırlık bir kod ediyormuş =)
Konsolda şuradaki komutu verin. Tahmin edebileceğiniz gibi pygame sistemde kurulu olmalı.

22 Kasım 2008 Cumartesi

Kod aramak

Ben her hangi bir konuda kod örneği bulmak için şu siteleri kullanıyorum, sizin de işinize yarayabilir.

11 Kasım 2008 Salı

setup.py Dosyası hazırlamak

Bu yazımızda python un distutils (distutils.core.setup) modülü ile kurulum betiği hazırlayacağız...

distutils modülü öntanımlı olarak python ile gelmektedir.

Öncelikle setup.py den biraz bahsedeilm: çoğu python uygulaması distutils ile kurulum betikleri hazırlar, bunun nedeni distutils in sorunsuz, kolay ve tabi ki python ile birlikte geliyor olması diyebiliriz. :D

Şimdi betiğimizi yazalım:


# -*- coding: utf-8 -*-
# setup.py denemesi...

from distutils.core import setup # distutils.core modülündeki setup metodununu çağırıyoruz...

# simge gibi şeyleri tanımlıyoruz...
datas = [("share/applications", ["data/kxmp.desktop"]), ("share/pixmaps", ["kxmp/kxmp.png"])]

setup(name = "kxmp",
version = "0.1.2",
description = "Graphical xm player...",
author = "Oğuzhan Eroğlu",
author_email = "oguzhan@oguzhaneroglu.com",
url = "http://kxmp.googlecode.com",
packages = ["kxmp"],
data_files = datas,
scripts = ["data/kxmp"])


Şimdi de kodu açıklayalım:
setup argumanları:

  • name: Uygulamanın adı.
  • version: Uygulamanın sürüm numarası (str olmalı)
  • description: Uygulamanın ne yaptığını anlatan kısa bir açıklama.
  • author: Yazarın adı.
  • author_email: Yazarın e-posta adresi.
  • url: Uygulamanın proje sayfası.
  • packages: Uygulamanın kaynak kodlarının bulunduğu yani kurulacak dizinler (liste olmalı)
  • data_files: Uygulamanın çalıştırma dosyası, .desktop gibi dosyaların bulunduğu dizin. (liste olmalı)
  • scripts: /usr/bin altına gidecek betikler. (liste olmalı)

burdan önemli noktalara değinecek olursak:
packages
, data_files, scripts argumanları liste olmalıdır, çünkü bu tür dizinler birden fazla da olabilir.

datas değişkenini açıklayacak olursak:
yapılan işlem şu liste içerisine bilgiler ("hedefdizin", [kaynakdizinler]) şeklinde veriliyor.

ve dikkat ettiyseniz setup hep /usr/ altında çalışır yani /usr/share/applications yazmak yerine share/applications yazarız.

Yaptığı şeye değinecek olursak çok basit kodlarınızı site-packages dizinine atıyor... yani uygulamayı çalıştıracak betik sadece import a dese yeterli (a burada packages argumanına verilen dizinlerden biri).

İyi çalışmalar...

Python projesinde klasör yapısı

Bunları yap:

  • Projenizin en üst dizininin adı projenizle aynı olsun, - işareti ile birlikte versiyonu belirtin. Örneğin projenin adı Twisted ise root klasörünüz Twisted-2.5 gibi birşey olabilir.
  • Twisted/bin dizinini oluşturun, ve eğer var ise çalıştırılabilir dosyalarınızı buraya koyun. Eğer çalıştırılabilir dosyanız bir python kodu ise soy adından .py ifadesini kaldırın. Bahsi geçen Python kodu dizin yapınız içerisinde başka bir yerde duran main fonksiyonunu çağırmaktan başka bir işe yarıyor olmamalı.
  • Projeniz tek bir Python betiğinden oluşuyor ise bunu kök dizininize projenizle aynı ismi vererek yerleştirin. Örneğin: Twisted-2.5/Twisted.py
  • Projeniz birden fazla Python kaynak kodundan oluşuyor ise kök dizininiz altında bir paket (python pakedi) oluşturun (Twisted-2.5/twisted klasörü oluşturup içine __init__.py dosyası koyun) ve kodlarınızı buraya yerleştirin. Örneğin Twisted-2.5/twisted/internet.py
  • Test araçlarınızı kök dizin içerisinde başka bir paket içerisine koyun (Twisted-2.5/tests/). Örneğin önceki örnekteki Twisted-2.5/twisted/internet.py yi test eden test-internet.py yi buraya koyun.
  • Kök dizininize README gibi dosyaları ve setup.py nizi yerleştirin.
Bunları yapma:
  • Kodlarını src yada lib gibi klasörlere koyma bu progamı yerleştirmeden (install etmeden) çalıştırılmasını zorlaştırır.
  • Pakedin içindeki Python betiklerini test eden python betiklerini pakedin içinden başka bir pakedin içine koymaz iseniz kurulum yapıldıktan sonra testleri yapmak zorlaşacaktır.
  • Bir paket oluşturup sadece __init__.py içerisine fonksiyonları dizeceksen bunun yerine bir modül oluşturman çok daha kolay olur.
Kaynak : http://jcalderone.livejournal.com/39794.html

30 Ekim 2008 Perşembe

Google App Engine uygulama geliştirme 2

Google App Engine ile uygulama geliştirmenin ikinci sayısında aslında sizlere apilerden bahsedecektim ama farklı konulardan bahsedeceğim. Bunlar;

1. Google App Engine Django Kurulumu
2. Google App Engine ve Django Form Yaratma
3. Formları İşleme Ziyaretçi Defteri Uygulaması

Hiç laf ebeliği yapmadan olaya giriyorum çünkü uzun bir yazı olacak.

1. Google App Engine Django Kurulumu:
Öncelikle şunu söylemeliyim, Appengine'nin kendi web çatısı var ancak, dökümasyonu djangonun çok iyi ve sadece dökümasyon ile sınırlayamam artılarını. Bir kaç sebebden olsa gerek ısrarla django ile çalışıyorum appenginede. Şimdi sıra sıra nasıl Google'ın beleş uygulama motorunda çalışacağını görelim.

a) django-admin.py startproject yetis şeklinde bir proje başlattık. Ayrıntılara takılmayın isimler saçma bende profesyonel kodcu değilim :D

b) main.py

c) settings.py

d) app.yaml

application: app_engine_domain_adi
version: 1
runtime: python
api_version: 1

handlers:
- url: /.*
script: main.py

app.yaml dosyası hakkında daha önce neyin ne olduğunu anlatmıştım ve linklerde vermiştim bu sebebden dolayı bir daha üzerinden geçmiyeceğim. Şimdi bir deneme yapın ekranda django falan diyecek :D google_appengine/dev_appserver.py dosyanin_bulundugu_yer

e) Artık bir uygulama başlata biliriz ortam uygun hale geldi :D
> cd yetis
> python manage.py startapp Blog
uygulamamızın adı Blog olsun...

Artık Django'yu Google App Engine'de kullanabilirsiniz.

2. Google App Engine ve Django Form Yaratma ve İşleme:
Bu konudan açarak bahsetmek istiyorum bu nedenle link vermiyeceğim. Django Form işleme,yaratma,düzenlemenin Appengine'ye uyarlamasıdır, yani bu uygulama Django içindir Appengine sadece çalıştırır :D

Karışıklığı önlemek için dosya yapısının tree'sini veriyorum.
|----- app.yaml
|----- index.yaml
|----- main.py
`----- yetis
------|----- Blog
------|----|----- bform.py
------|----|----- models.py
------|----|----- templates
------|--------------- ziyaretci.html
------|--------- views.py
------|----- manage.py
------|----- settings.py
------------ urls.py

Django ile proje başlattık ( yetis ) ve birde uygulama açtık ( Blog ) . Şimdi sıra ile gidelim
a) Model oluşturulacak
b) Model için Form oluşturulacak

a) Model Oluşturulacak:
Modelimizi bir ziyaretçi defteri oluşturma uygulamasına göre oluşturuyorum.

from google.appengine.ext import db
class Z_Defteri(db.Model):
ad = db.StringProperty(verbose_name="Ad",required=True)
soyad = db.StringProperty(verbose_name="Soyad",required=True)
not_ = db.TextProperty(verbose_name="Mesaj")
inci = db.IntegerProperty(default = 0)
tarih = db.DateTimeProperty(auto_now_add = 1)
yazan = db.UserProperty()

def __unicode__(self):
return "%s %s %s %s"%(self.not_,self.ad,self.soyad,self.inci)

Modeldeki alanların parantezleri içindeki değişkenlerden bahsedelim.
verbose_name = "Ad" ----> Tablom oluştuğunda alanın ismini "Ad" yaptım. Yani şurası; <input type="text" name="ad" id="id_ad"
Peki neden bunu yaptık. Tabloya müdahale gücümüzü arttırmak için. Biz isim vermezsek kendisi uygun bir isim atıyacaktı zaten. Bunu neden biz yapmayalım :D
required = True ----> Bu özellik bizi zahmetten kurtarıyor. Şimdi bu alan gerekli mi_? gereksiz mi_? bir diğer değişle, bu alan hiç girilmesede olur mu? Bunu belirlemek için şöye dedik : luzumlu = Evet işte bunu söylüyoruz. Peki neden! Hata takibi yapmak için, eğer kullanıcı benım oluşturduğum bir tablonun alanını es geçerse ben ona hopbala, burayı doldurmadan geçiş izni yok diyorum :)
default = 0 ---> Ön tanımlı olarak sıfır değerini alsın.
auto_now_add = 1 ---> Tarihi commit yaptığımda otomatik oluştur.


b) Model için Form oluşturulacak:
Nedir! Ne değildir! Model için Form derken Modelin alanları için işlem yapabileceğim bir form alanı oluşturmakdan bahsediyoruz. Bunu el ile de yapabilirsiniz ama neden yapasınız! Bir sürü koddan ve hata takibinden kurtuluyorsunuz. Başlayalım! Öncelikle bform.py adında bir dosya oluşturalım. Dosyanın nerede oluştuğunu yukardaki tree'e bakarak görebilirsiniz.
bform.py

from models import Z_Defteri
from google.appengine.ext.db import djangoforms

class ZD_Form(djangoforms.ModelForm):
class Meta:
model = Z_Defteri
fields = ('ad','soyad','not_','tarih',)
exclude = ['inci','yazan']

----> "from models import Z_Defteri" ile modelimizin aldık
----> "from google.appengine.ext.db import djangoforms" Appengine'nin django'da bulunan ModelForm olayını kullanmamızı sağlayan modulunu aldık.
----> ZD_Form sınıfımıza djangoforms.ModelForm miras atadık. Buradaki ModelForm django'da 1.0 da var. Önceki versiyonunda yok 0,96 da NewForm olsa gerek :D
Öntanımlı değişkenlerden bahsedeyim.
-----> model = Z_Defteri burada modelimizdeki değişkenleri atadık
-----> fields = ('ad','soyad','not_','tarih',) kullanacağımız alanlar
-----> exclude = ['inci','yazan'] ilk form oluştuğunda form'da gözükmesini istemediğimiz alanlar.

bform.py dosyasının içine bu uygulamada kullanacağınız butun formları atabilirsiniz. Böylelikle herşey toparlı olmuş olur.
3. Formları İşleme Ziyaretçi Defteri Uygulaması
İstediğimiz model için istediğimiz formu oluşturduk. Şimdi bu oluşturduğumuz formu ekranda göstermek ve kayıt, düzenleme, silme gibi uygulamaları yapmak kaldı. Burada sadece kayıt olayını ele alacağım. Ziyaretçi defteri uygulaması örneği üzerinde form işlemeyi göreceksiniz!

Bunun için üzerinde değişiklik yapacağım dosyalar. template klasöründeki ziyaretci.html dosyası, Blog uygulamasındaki views.py ve yetis projesindeki urls.py dosyalarıdır. Yukardaki tree'ye göre dosyaların yerlerini tesbit edebilirsiniz.
Öncelikle views.py dosyası:

from django.http import HttpResponse, HttpResponseRedirect
from yetis.Blog.models import Z_Defteri
from bform import ZD_Form
from django.shortcuts import render_to_response
from google.appengine.ext import db
from google.appengine.api import users

Formları oluşturduğumuz yer bform.py den ZD_Form'u çektik, users,db apilerini ekledik, djangonun bir kaç fonksiyonunu ekledik.

def ziyaretci_defteri(request):
yazilanlar = Z_Defteri.all()
yazilanlar.order("-tarih")
yazilanlar = yazilanlar.fetch(10)

kullanici = users.get_current_user()
ndform=''
if kullanici:
k_islem = ("Hosgeldiniz, %s! (<a href=\"%s\">Cikis Yap</a>)" %(kullanici.nickname(), users.create_logout_url("/")))

if request.method == "POST":
zdform = ZD_Form(request.POST)
if ndform.is_valid():
yazan = kullanici
inc =Z_Defteri.all()
inci = inc.count()
not_ = (request.POST["not_"]).decode("utf8")
ad = (request.POST["ad"]).decode("utf8")
soyad = (request.POST["soyad"]).decode("utf8")
kayit = Z_Defteri(not_=not_,ad=ad,soyad=soyad,inci=inci,yazan=yazan)
kayit.put()
return HttpResponseRedirect('/')
else:
zdform = ZD_Form()

else:
k_islem = ("<a href=\"%s\">Giris Yapiniz</a>." % users.create_login_url("/"))

return render_to_response('ziyaretci.html',{'zdform':zdform,'yazilanlar':yazilanlar,'k_islem':k_islem,'kullanici':kullanici} )

Algoritması!
--->Önce sayfaya giren kişinin google kullanıcısı olup olmadığına bakıyoruz,
-------> google kullanıcısı ise ziyaretçi defterine not bırakmasına izin veriyoruz
-------------> Eğer Post ediliyor ve mothodumuz POST ise Form oluştur
-------------------->submit tuşuna basılmış ve Form boş bırakılmamışsa
-------------------------->Veritabanına Formda girilen alanları yaz.
-------------> Post edilmemiş ise sadece Form oluştur
--->değil ise google giriş sayfasına yönlendiriyoruz giriş yapıp tekrar yönlendirilsin.
Değişkenleri anlatacağım;
yazilanlar --> Ziyaretçi defterine yazılan yazının argümanlarının tamamını sorgu ile çekiyor.
kullanici --> Sayfayı ziyaret eden kişi. Dilerse deftere birşeyler yazabilir.
k_islem --> kullanici işemleri. Giriş ve Çıkış işlemi sadece :D
zdform --> Ziyaretçi Defteri form bilgilerini bu değişken ile alıyoruz. Form bu değişkende oluşuyor.

Burada daha fazla derine inmiyeceğim. Django'dan anlıyan arkadaşlar anlamışlardır diye umut ediyorum. Appengine kullanan arkadaşlar ise yeterince açıklayıcı olduğumu düşünüyorum.Sıra tempaltes kısmına geldi. Web sayfasında göstermek ve güzel görüntü oluşturmak için template kullanıyoruz.
Blog uygulaması içine bir templates klasörü açın ve içine ziyaretci.html dosyası açın. İçeriğinin bir kısmını bilgi amaçlı olarak burada, geri kalan tamamının linkini vereceğim.
en üstte {{k_islem}} koyarak kullanıcının gmail kullanıcı olup olmadığına bakarak yönlendirebiliriz.

<form action="." method="post">
<table>
{{zdform}}
</table>
<table>
<input type="submit" name="gonder" value="Gönder" class="inputsag"/>
</table>
</form>

Formumuz bu şekilde ekranda gözüktü :D zdform.as_b derseniz "b" halinde zdform.as_ul "ul" şeklinde zdform.as_table ise "table" şeklinde form oluşturur. Hiç birşey yapmazsanız sadece form oluşur.


{% for not in yazilanlar %}
<table>
<TD>
<p id="kisi">{{not.ad}} {{not.soyad}} <hr>
<em> id="eposta">{{not.yazan.email}}</em>
<em id="tarih">{{not.tarih|date:"d M Y D"}}</em></p>
<p> id="mesaj">{{not.not_}}</p>
</table>
</TD>
{% endfor %}

burada appengine ait olan yer "not.yazan.email" kısmıdır. Kullanıcının email adresini yazdırıyorum."not.tarih|date:"d M Y D"" burada ise tarihi filitre ederek ekrana basıyorum.
html dosyasının kod kısmı buradan ibarettir.

Çalışır halini görmek için

http://pythonizm.appspot.com



referanslar:
1- http://code.google.com/appengine/docs/datastore/creatinggettinganddeletingdata.html
2- http://appengineguy.com/2008/06/proper-unit-testing-of-app-enginedjango.html
3- http://www.djangobook.com/en/1.0/chapter07/
4- http://docs.djangoproject.com/en/dev/ref/forms/fields/
5- http://code.google.com/appengine/articles/django.html

21 Ekim 2008 Salı

Djangoya nasıl başlanmalı nasıl ilerlemeli ?

Bu konuda herkesin farklı görüşleri olabilir fakat benim edindiğim tecrübeler yardımıyla yeni başlamak isteyenler ve başlamış olup da nasıl devam etmesi gerektiği konusunda düşünceleri olan arkadaşlar aşağıdaki yollardan faydalanarak daha verimli gelişim gösterebilirler.

1) Buradan başlayın. Bir çok yerde djangobook ile başlamanız tavsiye edilir ama şu anki haliyle djangobook çok eksik kalmaktadır. Özellikle django 1.0'ın çıkmasıyla örneklerin bir çoğunu çalıştırmak için 1001 türlü takla atmanız gerekebilir.

2) 4 bölümden oluşan django tutorial'ı iyice anladığınıza inanıyorsanız. Django dökümantasyonuna geçebilirsiniz. Üstünde uzmanlaşmak istediğiniz alana göre buradan faydalanabilirsiniz.

3) How-to lardan inceleyebilirsiniz.

4) Dökümantasyonda ve how-to da anlatılanları aştınız ve ayrıntılara girmek istiyorsanız. Fonksiyonlar, sınıflar ve django ile ilgili her türlü ayrıntı için burayı ziyaret edebilirsiniz.

5) Yeni sürümlerle gelen özellikleri ve değişiklikleri takip etmek için burayı Herşeyi aştım birazda katkıda bulanayım diyorsanız da burayı ziyaret edebilirsiniz.

Sizin de eklemek istedikleriniz olursa tecrübelerinizi ve önerilerinizi yorumlar kısmında paylaşmanızdan memnuniyet duyacağız ;)

Bunlar yanında bizi izlemeye devam edebilirsiniz :)

20 Ekim 2008 Pazartesi

İlişkisel Alanlar (Relationship Fields)

ForeignKey
Aşağıda foreingkey'in kullanımını anlatmak amacıyla yazılmış ufak bir örnek göreceksiniz.

from django.db import models

class Yazar(models.Model):
isim = models.CharField(max_length=30) #[1]

class Makale(models.Model):
baslik = models.CharField(max_length=100) #[2]
yazar = models.ForeignKey(Yazar) #[3]


[1] Yazar tablosunda CharField veri türünde bir alan oluşturuyoruz.
[2] Makale tablosunda CharField veri türünde bir alan oluşturuyoruz.
[3] Bu alanda ise ForeignKey(Yazar) ifadesi djangoya Makale tablosuna Yazar tablosunun Primary_Key'i ni eklemesini söylüyor. Daha iyi anlaşılması için şöyle örneklendirebiliriz.


Yazar
id--|--isim--|
1 --|Mirat---|
2 --|Gokmen--|
3 --|Deniz---|

Makale
id--|--baslik--|--yazar_id--|
1---|Django----|-----1------|
2---|Python----|-----1------|
3---|PyQt------|-----3------|

Id ile gösterilene alanlar tablomuzun PrimaryKeyleri. Biz eklememiş olmamıza rağmen django otomatik olarak bir PrimaryKey alanı oluşturuyor.
Makale tablosunda ki yazar_id alanı ise bizim Makale sınıfını oluştururken kullandığımız ForeignKey(Yazar) ifadesiyle Makale tablosuna Yazar_id adında bir alan ekliyor ve bu alanlar arasında ilişki kurmamızı sağlıyor. Makale tablosundaki yazar_id alanını yazar tablosundaki id ile eşleştirmemizi sağlıyor.Yani Django ve Python yazılarının sahibi yazar id si 1 olan Mirat'a aitken PyQt yazısı yazar id'si 3 olan bana ait. (Aslında bu konu djangodan çok ilişkisel veri tabanıyla alakalı olduğu için daha ayrıntılı bilgi için google kullanabilirsiniz ;) )

Şimdi djangoyu ilgilendiren kısımlarına gelelim.

Eğer ForeignKey'imiz başka bir uygulamadan çağırılacaksa uygulama ismiyle beraber belirtmemiz gerekiyor. (Django 1.0 dan önceki versiyonlarda bu özelliği kullanamıyorsunuz)


class ornek(models.Model)
yazar = model.ForeignKey('uygulama.tabloadi')


ManyToManyField
Yukarıda foreignkey ile onetomany bir ilişkinin nasıl sağlanacağını gördük. Fakat bazı durumlar vardır ki One-to-Many ile işin içinden çıkamayız. Az önceki örneğimizi biraz değiştirelim ve kitap bilgilerini ve yazarlarını tutan bir uygulama haline çevirelim. İlk örneğimizde bir yazar (one) bir kaç makale(many) yazabiliyordu. Yani makale tablosunda aynı yazar id'sinden birden çok(many) bulunabiliyordu. Peki ya bir kitabın birden çok yazarı olduğu durumlarda ne yapacağız ? Bu gibi durumlarda manytomany ilişkilerini kullabiliriz.


from django.db import models

class Yazar(models.Model):
isim = models.CharField(max_length=30)

class Kitap(models.Model):
baslik = models.CharField(max_length=100)
yazar = models.ManyToMany(Yazar)


Böyle bir ifadeyle django bu manytomany türü ilişkiyi sağlayabilmek için ayrı bir tablo oluşturuyor ve gerekli olan ilişkileri kendisi kuruyor. Bu tablo genelde iki tablonun isimlerinin birleştirilmesiyle oluşuyor. Yani bizim örneğimizde yazar_kitap şeklinde bir tablo oluşturup içerisine yazar_id ve kitap_id alanlarını ekleyip gerekli olan ilişkileri kendisi sağlıyor. Yani yukarıda ki kod veritabanımıza şu şekilde yansıyor.

Yazar
id--|--isim--|
1 --|Mirat---|
2 --|Gokmen--|
3 --|Deniz---|

Kitap
id--|--baslik--|
1---|Django----|
2---|Python----|
3---|PyQt------|

yazarkitap
id--|--yazar_id--|--kitap_id--|
1---|----1------|-----1------|
2---|----1------|-----2------|
3---|----2------|-----3------|
4---|----3------|-----1------|

Şimdi bizden Django kitabının yazarları istediğinde kitap tablosundan 1'idsini alıp yazar kitap tablosundan karşılık gelen yazar idlerini alıyoruz(1 ve 3)
yazar tablosundan da o id'ye karşılık gelen değerleri öğreniyoruz.(Mirat ve Deniz).

İşte manytomany böyle birşey. Olabildiğince basitleştirmeye çalıştım. Eğer hala mantığı tam olarak anlayamadıysanız tek bir cümleyi aklınızdan çıkarmayın. "Eğer bir değer 2 tabloda da birden çok kez yer alıyorsa manytomany kullanmalısınız"

Manytomany ve diğer veritabanı incelikleriyle ilgili anlatılacak çok şey var ama şimdilik burda kesiyorum. Ayrıntılı bilgi için kaynaklar bölümündeki adresleri ziyaret edebilirsiniz. Fırsatım oldukça yeni yazılarda eklemeyi düşünüyorum.

Kaynaklar: http://docs.djangoproject.com/en/dev/ref/models/fields/
http://www.djangoproject.com/documentation/models/
http://docs.djangoproject.com/en/dev/topics/db/models/

14 Ekim 2008 Salı

Django model veri tipleri

Bir veri tipi belirlerken dikkat etmeniz gereken 2 şey vardır:
  1. Field ismini rezerve edilmiş python kelimesi olamaz.
  2. Field ismi birden fazla alt çizgi ("_") işareti barındıramaz.
Field sınıfları 3 şeyi ifade etmek için kullanılır.
  • Database sütün tipi (örn: INTEGER, VARCHAR, INT...)
  • Django yönetici panelinin kullandığı her hangi bir widget (örn: )
  • Django yönetici panelinin minimal doğruluk gereklilikleri.
Şimdi bu alan tiplerine değinelim.

AutoField


Sayısal bir alan olup veri tabanındaki kayıtların artmasıyla otomatik olarak arttırılır. Büyük ihtimalle doğrudan kullanmanız gerekmeyecek; aksini belirtmediğiniz taktirde modelinize bir "primary key field" zaten ekleniyor. (:S Bu kısmı benden daha iyi anlayan biri varsa lütfen yorum olarak eklesin bilgilerini)

BooleanField


Doğru/Yanlış (True/False) bilgisi tutar.

CharField


Karakter katarı tutar çok uzun bir metin tutulacaksa bunun yerine TextField kullanılmalıdır.

Charfield fazladan bir parametreye ihtiyaç duyar : maxlength, bu alanınızın en fazla kaç karakterlik veriyi tutabileceğini ifade eder.

CommaSeparatedIntegerField


Virgülle ayrılmış sayıların tutulduğu bir alandır. Charfield gibi maxlength argümanına ihtiyaç duyar.

DateField


Tarih tutmak için kullanılan bir alandır. İki adet seçimlik argümanı vardır. Bunlar :
auto_now
Otomatik olarak kayıt edilme tarihini tutar. save() komutunu verdiğinizde tarih ne ise alanınız o tarih ile otomatik olarak kaydedilecektir.

auto_now_add
Otomatik olarak nesnenin ilk yaratıldığı tarihi tutar.


DateTimeField:


Tarih ve saat bilgisini tutar. DateField la aynı seçimlik argümanları kullanır.

EmailField


Email adresi tutmak için kullanılır. Email adresinin doğru olup olmadığı otomatik olarak kontrol edilir. maxlength argümanını kabul etmez en fazla uzunluk 75 karakter olarak sabitlenmiştir.

FileField


Bir dosya upload alanıdır. Sadece bir gerekli argümana sahiptir.
upload_to:
Yerel dosya sistemi yolu olup config dosyanızdaki MEDIA_ROOT yolu ile birleştirilip kullanılacaktır.


Bu yol strftime içerebilir. Örneğin MEDIA_ROOT dizininz /home/media olarak ayarlanmış olsun. upload_to parametresini "photos/%Y/%m/%d" olarak verirseniz. Django buradaki zaman damgalarını upload edilme tarihinden bakarak doldurur. (Örneğin %Y yıl'ın 4 basamaklı hali ile değiştirilir)

FileField ve ImageField alanlarını kullanmak için


  1. Ayarlar dosyanızda MEDOA_ROOT dizini Django'nun upload edilen dosyaları nereye koyacağını belirler. Buraya tam yolu yazın.
  2. Modelinize FileField veya ImageField ekleyin, upload_to argümanının dosyaların MEDIA_ROOT altında hangi alt dizine gideceğini belirlediğini unutmayın.
  3. Dosyanız kayıt edilden sonra Django size get__url fonksiyon sunar. Örneğin ImageField kayıdınızın adı profile_picture ise template dosyanızda {{ object.get_profile_picture_url }} şeklinde url'li kullanabilirsiniz.


Eğer dosyanın disk üzerindeki yerini, dosya boyutunu vs. öğrenmek isterseniz get_FIELD_filename(), get_FIELD_size() gibi fonksiyonları kullanabilirsiniz ayrıntılı bilgi için Djangobook'un Appendix C bölümüne bakın.

FilePathField


Seçimleri dosya sistemiz üzerindeki dosyalarla sınırlı olan bir alandır. Üç özel argümana sahiptir.
path
Gerekli, sistemdeki her hangi bir klasörü gösteren tam yol.

match
Seçimlik, bahsi geçen klasör içerisinde hangi dosyaları seçeceğini gösteren düzenli ifade.

recursive:

Seçimlik, True ise match ifadesi alt dizinlerde de aranır. False olarak öntanımlanmıştır.


Örnek: FilePathField(path="/home/texts", match="*.txt", recursive=True)

FloatField


Kayar noktalı sayı başka bir değişle ondalıklı sayı tutmak için kullanılır. Python'daki karşılığı float veri tipidir. İki adet argüman kullanır.
max_digits
Sayının en fazla sahip olabileceği basamak sayısı.

decimal_places
Sayının ondalıklı kısmının kaç basamaklı olacağını belirler.


ImageField


FileField ile aynıdır fakat upload edilen nesnenin doğru bir imaj olup olmadığını kontrol eder. Bunun yanında height_field ve width_field adında iki fazladan argümana sahiptir. Bu argümanlar imaj kaydedilirken otomatik olarak üretilip kaydedilirler. Bunun yanında FileField metodları (get_FIELD_*) burada da geçerli olup bunlara ek olarak get_FIELD_width() ve get_FIELD_height() metodları da ek olarak bulunmaktadır.

IntegerField


Tamsayı tutar.

IpAdressField


Bir ip adresini karakter katarı olarak tutar (örn: "127.0.0.1")

NullBooleanField


BooleanField gibir fakat bunun yanına bir adet de None değeri eklenmiştir. True/False/None değerlerini tutabilir.

PhoneNumberField


Özelleştirilmiş bir CharField tipidir fakat ek olarak girilen metnin U.S. tipi telefon numarası biçimlemesine uyup uymadığına bakar (XXX-XXX-XXXX)

Not: Başka bir ülkenin telefon numarasını kontrol etmek isterseniz django.contrib.localflavor pakedine bir göz atın.

PositiveIntegerField


IntegerField ile aynıdır fakat sadece pozitif tamsayıları tutar.

PositiveSmallIntegerField


PositiveIntegerField gibidir fakat belirli bir sayıya kadar izin verir. Maksimum değer kullandığınız veri tabanın SMALLINT veri tipinin pozitif olarak ulaşabildiği kullanabildiği maksimum (Genellikle 65535) değerdir.

SlugField


Slug ingilizce bir gazetecilik terimidir. Her hangi bir şey için kısa bir etiket olabilir. Sadece harf,sayı ve alt çizgi karakteri içerebilir. Genelde URLler tarafından kullanılır. Örneğin bir bloglarda görmüşsünüzdür "Hırsızlar Nerede?" başlığı ile kaydettiğiniz yazı url'de "hirsizlar-nerede" şeklinde gözükür. İşte başlığın çeşidine slug diyoruz. (bu kısım hakkında benden daha fazla bilgisi olan lütfen yorum olarak eklesin.)

CharField da olduğu gibi maxlength parametresi alabilir eğer almadıysa öntanımlı maxlenth parametresi 50 karakterdir.

Slugfield prepopulate_from adında fazladan bir seçeneğe sahiptir. Bu slug metninin, nesnenizin django admin panelindeki hangi alan(lar)ının birleşiminden otomatik olarak oluşturulacağını belirler. kullanımı models.SlugField(prepopulate_fpom=("pre_name", "name")) gibidir.

SmallIntegerField


PositiveSmallIntegerField'ın aynısıdır fakat buradaki sayı işaretlidir. Genellikle -32,768 ile +32,767 arasındaki sayıları ifade edebilir.

TextField


Sınırsız metin alanıdır.

TimeField


Günün saatini barındırabilen bir alandır. DateField ve DateTimeField'ın sahip olduğu otomatik oluşturma seçeneklerini bu da barındırır.

UrlField


Bir url tutmak için kullanılır. Eğer verify_exists argümanı True olarak geçirilirse adresin doğruluğu kontrol edilir (kontrol adrese ping atmak vasıtası ile gerçekleştirilir).

XmlField


TextField ile aynıdır fakat xml tutmak için kullanılır. Xml söz dizimini kontrol eder. Söz diziminin doğruluğunu kontrol etmek için RELAX NG şemasının yerini dosya yolu olarak vermeniz gerekmektedir.

11 Ekim 2008 Cumartesi

Google App Engine uygulama geliştirme 1

Son zamanlarda web programlama öğrenme azmimin sonunda galib geleceğimi ve bana çok uzak olan bu alanda kendime birşeyler katabileceğimi gösteriyor. Web programlama diyince akla gelen çatılara değiştirerek bir yenisini ekleyen ve iyiki olan Google'in APP ENGINE uygulaması ile web uygulamaları geliştirmeye bende başladım. Biraz araştırma, biraz deneme yanılma yöntemiyle mantığını azda olsa kavramış bulunmaktayım. App Engine yeni! djangoyu kullan, dökümasyonda sıkıntı çekersin veya sırf beleş hosting var o yüzden kullanıyorsun! diyenleri duyar gibiyim. Ne yalan söyleyim haklısınız ama önce aşağıdakileri okuyun.

  • 500 mb web alanı,

  • 9 tane app engine uygulaması açabilirsiniz ki bu toplamda 4500 mb'lık web alanı demek,

  • Aylık 5 milyon sayfa gösterimi için her App Engine uygulaması 500 mb'a kadar depo, yeterli band genişliği ve cpu kullanamı sağlıyor.

  • Uygulama version takip sistemi. Bunu alatmak zevkli olacak çünkü herkezin hoşuna gideceğine inanıyorum. Buraya bir yıldız atalım ve aşağıda anlatalım. *Version Takip

  • Google App Engine admin panelini unutmamış, istatistiklerin tutulduğu, version seçiminin yapılabildiği ve dilerseniz uygulamanıza varsa Domain adresinizle bütünleştirebilirsiniz. Bunlarla artı olarak milyonlarca tabloyu yönetmek için veri gösterim bölümü var(data viewer)... Uygulamanızın çalışma esnasındaki Log'larınızı takip edebilir ve hataları görebilirsiniz.

  • App Engine'nin bir özelliği daha çok hoşuma gidiyor. Henüz kullanmak nasip olmadı ama:D Admin panelini incelerseniz orada Developers yazan bir kısım var. Geliştiriciler bölümünde projenize istediğiniz kadar kullanıcıyı dahil edebilir ve ortak bir çatı altında uygulamalarınızı yönetebilirsiniz. Tek yapmanız gereken geliştirici olacak kişinin gmail adresini buraya yazmak.

  • Modeller,Template,Static dosyaları, kendi web uygulamaları için frameworkü ve en güzeli baştan aşağıya python ile web uygulamaları geliştirebileceğiniz açık kaynak kodlu güzel bir çalışma ortamı ve sağlayıcısı.


*Version Takip Açıklaması : Benim çok hoşuma giden ve sizinde çok hoşunuza gideceğine inandığım bir uygulamadan bahsedeceğim. Appengine'de ayar dosyasında şöyle birşey vardır.

application: gencistatistik
version: 2
runtime: python
api_version: 1


  • application kısmı uygulamamızın AppEngine'deki adını yazılıyor

  • runtime kısmı uygulamanın hangi dili kullandığını

  • api_version api versionudur. Bu kısmı pek anlamış değilim

  • version bu kısımda projenizi versionlara ayırabilirsiniz.

  • Örneğin bir blog uygulaması yapıyorsunuz. Geliştirdiğiniz blog uygulamanızı makinanızda google_appengine/dev_appserver.py sitem/ şeklinde test ettiniz hiç bir sorun yok, o zaman dediniz ki ben bunu geliştireceğim ve bunun üzerine gelişmiş versionlar koyacağım. Appengine size bu fırsatı tanıyor ve version kısmına 1 yazarsanız her alanınıza yüklediğinizde(google_appengine/appcfg.py update sitem/) 1 ve üstü versionlar olur. Diyelimki artık blog uygulamanız yeterince gelişti ve siz hataları görmek için 1 sürümünü kaldırmadan version kımına 2 yazdınız ve alanınıza yüklediniz. App Engine'de artık hem 1. ve hem 2. sürümler mevcut. Admin panelinden hangisini öntanımlı(default) version olarak seçerseniz o sürüm uygulama.appengine.com adresinde gözükür. Diğeri ise geliştiriciler tarafından test etmek amacı ile kullanılabilir. Süper değil mi? :D


    İştahınızın kabardığını düşünüyorum ve birazda icraat dediğinizi duyuyorum. Açıkcası bu yazıyı yazmadan 1 gün önce appengine ile merhabalaştım :D bir gün sonra küçük bir blog uygulaması yaptım.( http://gencistatistik.appspot.com/ ) Nereden başlıyacağınızı bilmiyorsanız pytr.org adresinde güzel referans olarak kabul ediyorum. Çok güzel bir anlatım tarzıyla konuyu özetlemişler, nasıl hesap alacağınızı, nereden başlıyacağınızı, kavramları ve başlangıç teknikleri. ( TIKLA )

    Django kullanan arkadaşlarımın çabuk adapte olacağına inanıyorum. Ben uygulamamda django kullanarak değil App Engine'nin kendi Framework'ünü kullanıyorum. Kendi blog adresimden bir örnek ile bitirmek hayırlı olacak uzadıkça uzuyor :D Öncelikle pytr.org adresindeki makaleleri okuduğunuzu varsayıyorum.
    Dosyanın içerik listesi.
    mysite
    ------>static
    ------>python
    -------------->templates
    ---------------------------->blogyaz.html
    ---------------------------->index.html
    -------------->hello.py
    ------>app.yaml
    Python dosyası sadece bir tane var. Bütün python kodları aynı yerde, parçalamadım.

    from google.appengine.ext import webapp
    from google.appengine.ext.webapp.util import run_wsgi_app
    from google.appengine.api import users
    from google.appengine.ext import db
    from google.appengine.ext.webapp import template
    #Blog uygulamamda kullanmak için tablolarım.
    class Blogum(db.Model):
    yazan = db.UserProperty()
    girdi = db.TextProperty()
    blogbaslik = db.StringProperty()
    date = db.DateTimeProperty(auto_now_add=True)

    class Karsilama(db.Model):
    yazan = db.UserProperty()
    yazi = db.StringProperty(multiline=True)
    date = db.DateTimeProperty(auto_now_add=True)

    Kısaca Blogum ve Karsilama tabloları oluşturdum. Appenginede djangoda olduğu gibi modeli oluşturmama gerek yok. İsterseniz çalışma anında dahi tablolara müdahale edebilirsiniz :D Karsilama gelen kişiye mesaj yazma veya algılama için oluşturdum. Tablolar çok basit olabilir ama buda bir örnek :D

    class AnaSayfa(webapp.RequestHandler):
    def get(self):
    bloglar = Blogum.all()
    bloglar.order("-date")
    kullanici = users.get_current_user()
    if kullanici:
    url = users.create_logout_url(self.request.uri)
    url_linktext = "Çıkış"
    else:
    url = users.create_login_url(self.request.uri)
    url_linktext = "Giriş"
    template_values = {
    "bloglar":bloglar,
    "url":url,
    "url_linktext":url_linktext,
    "kullanici":kullanici}
    path = os.path.join(os.path.dirname(__file__), 'templates/index.html')
    self.response.out.write(template.render(path, template_values))

    Class'larımız eğer biz appenginenin kendi web çatısını kullancaksak miras alıyoruz. Burada miras olarak webapp sınıfının fonksiyonu RequestHandler'i aldık. get fonksiyonunda yolluyor post fonksiyonu ile gelen veriyi yorumluyoruz. bloglar = Blogum.all() ile blogum tablosuna sorgu çekiyor ve order("-date") ile güncel tarihe göre sıralatıyoruz. (SQL nerde :D) Modeller ve alanları ile ilgili daha geniş bilgi için TIKLA burayı biraz kurcalayın.
    kullanici = users.get_current_user() burada Appenginenin Users Api'sini kullandık ve get_current_user() ile en basit söylem ile giren üye mi? öğrendik :D Üye ise çıkış yapmasını , üye değil ise google'ın giriş sayfasına yönlendirdik.

    Path dosyasında index.html dosyasının yerini aldık ve self.response.out.write(template.render(path, template_values)) ile template sözlüğündeki anahtarları index.html dosyamızda kullanmak üzere yolladık :D Artık html dosyamız ile işlemlerimize devam edebiliriz. Şimdilik bu kadar yeter sindirin ve kurcalayın html dosyalarımızda yolladığımız bu anahtarları nasıl kullandığımızı, static dosya mantığı, app.yaml dosyasının mantığı, admin paneli ve inşallah Appengine'deki uygulamamın içinde google api'lerinin nasıl kullanıldığını anlatacağım. Eksiğim yanlışım veya düzeltilmesi gereken bir yer, konu veya mantık hatası varsa lütfen uyarınız.

2 Ekim 2008 Perşembe

Cgi-python'a Giriş

Bu yazımızda cgi modülünü ve cgi-python ile web sayfaları yazmayı anlatacağız.
Öncelikle python destekleyen bir yer bulmalısınız veya kendi bilgisayarınızda deneyebilirsiniz.


# -*- coding: utf-8 -*-

print """\
Content-Type: text/html\n

<html>
<body> bu bir deneme sayfasıdır... </body>
</html>
"""


cgi-python da html kodları print ile yazılır.
Content-Type: text/html\n satırı ile içeriğin türünü belirttik buradaki "\n" karakteri koyduk çünkü bu satırdan sonra 2 tane "\n" olmalı.

şimdi örneğimizi geliştirelim...


# -*- coding: utf-8 -*-

import cgi

form = cgi.FieldStorage()
isim = form.getfirst("isim", "bos")

print """\
Content-Type: text/html\n

<html>
<body>
<b>Gelen isim: </b> %s
</body>
</html>
""" % str(isim)


burada cgi modülündeki FieldStorage sınıfının getfirst metodu ile "isim" adındaki argumanı aldık bu arguman index.py?isim=deneme şeklinde gelir buradaki "deneme" argumandır.
getfirst e verilen 2. arguman ise hiçbir değer gelmezse isim değişkenine atanır yani değer verilmezse değişkenin değeri "bos" olur.

örneğimizi daha da geliştirecek olursak...


# -*- coding: utf-8 -*-
import cgi

form = cgi.FieldStorage()
isim = form.getfirst("isim", "bos")

print """\
Content-Type: text/html\n
<html>
<body>
"""

if isim != "bos":
print """\n
<b> Gelen isim: </b> %s
""" % isim
else:
print """\
<form action="deneme.py">
isminiz: <input type=text name="isim">
</form>
"""

Hata yakalma:

# -*- coding: utf-8 -*-

import cgi
import cgitb

cgitb.enable()

try:
open("olmayan_doysa", "r")
except:
cgitb.handler()

Hata yakalamak istediğmizde cgitb modülünü cgitb.enable() ile aktif ediyoruz daha sonra ise hata yakalandığında cgitb.handler() i çalıştırıyoruz.

1 Ekim 2008 Çarşamba

Mechanize Modülü ve Vodafon Örneği

Bildiğiniz gibi Vodafone kullancılarının günlük sadece bir mesaj hakkı vardır. Ancak bu mesaj hakkını 1 tane olmasından ve uğraşmak istemediğimizden kullanmayız. Bu python betiği ise üşengeç olup bir tanede olsa kullanırım diyenler için işe yarayabilir ama daha çok Python'dan anlayan insanların "Mechanize" modülüne örnek olması amaçlanmıştır.

Mechanize modülü kurulumu:
- Pardus'da konsoldan "sudo pisi it mechanize".
- Windows'da setup. direk kuruluma sahibtir.

#!/usr/bin/env python
#-*- coding:utf-8 -*-
import mechanize
#modülümüz yüklendi
def baglan():
global b
b=mechanize.Browser()
b.open('https://www.vodafone.com.tr/MyVodafone/login.php')
b.select_form(nr=1)


mechanize.Browser() ile tarayıcımızı oluşturduk, open ile sayfayı açtık, select_form ile sayfadaki 1. formu seçtik. Peki nedir bu form? Bu form bizim vodafona giriş için kullanacağımız kullanıcı adı ve şifresi bölümüdür. Daha açık bir şekilde bu form aşağıdaki gibidir;

>>> b.select_form(nr=1)
>>> print b
<browser visiting="" tr="" myvodafone="" php="" selected="">
<post tr="" myvodafone="" php="" application="" urlencoded="">
<textcontrol(gsmno=)>
<passwordcontrol(mypass=)>
</passwordcontrol(mypass=)></textcontrol(gsmno=)></post></browser>


Görüldüğü üzere sayfanın yukardan aşağıya doğru sıralamasında 1. form statüsünde olan formu seçtik çünkü vodafona giriş yapmak üzereyiz. Bu formda iki alan gözüküyor, bunlardan birincisi GsmNo diğeri MyPass. Sorumuz ise bu form girişlerini nasıl yapacağımız olacak !
Devam edelim!

def giris():
global b
gsmno=raw_input("GSM NO :") # numara girişi(543)
vodos=raw_input("Vodafon Şifreniz:") #-->şifre
b["GsmNo"]=gsmno # form girişi yapılıyor
b["MyPass"]=vodos
print "Bağlaniyor"
r=b.submit() # form bilgileri yollanıyor

try:
b.open('https://www.vodafone.com.tr/MyVodafone/myvodafone.php?pageId=WebSms') # websms sayfası
b.select_form(nr=1) #--------------->websms sayfasındaki (mesaj yollama) formumuz
except:
print "Bağlandi"
print "Hatalı Numara veya Şifre"
exit(1)

Buraya kadar yaptıklarımızı özetleyelim.
1. Vodafon sayfasını açıldı,
2. Vodafon sayfasına giriş yapıldı,
3. Girişimiz hatalı değil ise mesaj yollama sayfası açıldı,
Geriye sadece mesaj yollamak kaldı.
def mesaj_cek():
global b
try:
print "Mesaj Yollanacak Numaranın(Örn 543) kodu:"
yolk1=raw_input()
print "Mesaj Yollanacak Numara(Örn 4658758) kodu:"
yolk2=raw_input() #Örnein 4658758
try:
b["WebSimSmsUserGsmPrefix"]=[yolk1] #---->Numaramızın ilk 3 hanesi
b["WebSimSmsUserGsmNo"]=yolk2 #-------->Numaramızın devamı
except:
print "yanlis giris yaptiniz!"
exit(1)
print "Yollacak Mesajı Giriniz:"
mesaj=raw_input() #------------------------->Yollanacak mesaj
b["WebSimSmsText"]=mesaj #------------------>Mesajımız forma girildi
print "Mesaj yollanıyor"
r=b.submit() #------------------------------>Mesaj yollandı
print "Mesaj yollandı"
except:
print "GUNLUK SADECE 1 MESAJ HAKKINIZ VAR!!!"
exit(1)
b.close()
baglan()
giris()
mesaj_cek()


Bu kodun tamamı Burada
Neler yapılabilir;
  • Sınırsız mesaj sayfasından,sınırsız mesaj çekilebilir
  • Diğer operatörlerden benzer uygulamalar yapılabilir
  • Bayram,kandil,yıl başı gibi toplu mesaj atılmak istendiğinde bir veritabanı oluşturup,veritabanındaki listedeki kullanıcılara mesaj atılabilir
  • İstediğimiz web sayfasından istediğimiz bilgiyi alabilir ve web sayfalarını otomatikleştirebiliriz

Django Şablonları İçin Özel Etiketler

Django Şablonları İçin Özel Etiketler

İçeriğinde forum, günlük, anket vb. uygulamaların olduğu bir projeniz olduğunu düşünün. Ve siz forum uygulamasındaki son eklenen konuları, günlük uygulaması içerisinde kullanmak istiyorsunuz. Bu durumda ne yaparsınız? Günlük uygulamasının views.py dosyası içerisinden forum uygulaması tablosuna bağlanarak son eklenen konuları almazsınız umarım. Çünkü Django şablon dosyaları içerisinde, kendi yazdığımız etiketleri kullanabiliyoruz. Bu yazıda şablon dosyaları için uygulamanıza özel etiketleri nasıl oluşturacağınızı göstermeye çalışacağım.


İlk olarak projemizi ve uygulamamızı oluşturalım. Oluşturacağımız templates klasörü şablon dosyalarımızı, templatetags klasörü ise özel etiketlerimizle ilgili dosyaları içerisinde barındıracak.



$ djangoadmin.py startproject mysite
$ cd mysite
$ python manage.py startapp ozeletiketler
$ mkdir ozeletiketler/templates ozeletiketler/templatetags


Ardından settings.py dosyamızdaki TEMPLATE_DIRS ve INSTALLED_APPS ayarlarını düzenleyelim. Burada şablon dosyaları için proje dizinimizi hedef gösterdik. Bu şekilde Django, uygulamalarımızın altında bulunan templates ve templatetags klasörlerini tanıyabilecektir.




TEMPLATE_DIRS = (
[...]
'/home/omer/django-projects/mysite'
[...]
)


INSTALLED_APPS = (
[...]
'mysite.ozeletiketler'
)


Şimdide urls.py dosyamızı düzenleyelim.

urlpatterns = patterns('',
[...]
(r'^ozeletiketler/','mysite.ozeletiketler.views.index'),
[...]
)


Bu yaptığımız değişiklikleri test etmek için ozeletiketler uygulaması içindeki views.py dosyasını aşağıdaki gibi düzenliyor ve ardından templates klasöründe index.html dosyasını oluşturup tarayıcıda boş sayfa(ya da içine bir şeyler yazdıysanız onların) çıkıp çıkmadığını kontrol ediyoruz.



#-*- coding: utf-8 -*-
from django.shortcuts import render_to_response

def index(request):
return render_to_response('ozeletiketler/templates/index.html',{})
return render_to_response('index.html',{})


Boş sayfayı gördük, işler yolunda. Bir sonraki aşamaya geçelim. templatetags klasörü altında __init__.py ve ozeletiketler.py adlı dosyaları oluşturalım. __init__.py dosyası içeriği boş kalırken, ozeletiketler.py dosyası içeriği aşağıdaki şekilde olmalı.



#-*- coding: utf-8 -*-
from django.template import Library,Node

register = Library()

def beniyaz(veri):
return veri
register.simple_tag(beniyaz)


class IslemNode(Node):
def __init__(self,nodelist,bits):
self.nodelist = nodelist
self.bits = bits

def render(self,context):
islem = self.nodelist.render(context)
sonuc = eval(islem)
if self.bits.__len__()>1:
if self.bits[1] == 'sadece_sonuc':
return sonuc
return u"Yapılan İşlem %s : %s" %(islem,sonuc)

def islem(parser,token):
nodelist = parser.parse(('islembitti',))
parser.delete_first_token()
bits = token.contents.split(' ')
return IslemNode(nodelist,bits)
register.tag(islem)


Şimdi bu oluşturduğumuz özel etiketlerimizi şablon dosyamız içerisinde (önceden oluşturmuştuk: index.html) kullanalım.

{% load ozeletiketler %}

{% beniyaz "merhaba dünya" %}


{% islem %} 20 + 5 {% islembitti %}


{% islem sadece_sonuc %} 11 - 4 {% islembitti %}


Bu işlemin ardından http://127.0.0.1:8000/ozeletiketler/ adresini ziyaret ettiğinizde aşağıdaki çıktı ile karşılaşacaksınız:



Son olarak yapılan işlemlerle ilgili bazı konulara açıklık getirelim.

Ozeletiketler.py Dosyası

Library ve Node sınıflarını dahil ettik. Etiketleri kaydetmek için register değişkenine Library sınıfını atadık. Library sınıfı etiketleri şablon dosyaları içerisinde kullanabilmek için kaydetmemizi sağlar. Node sınıfı ise etiketlerin kullanılması ile gelen veriyi yorumlayıp geri döndürmeyi sağlar.

#-*- coding: utf-8 -*-
from django.template import Library,Node

register = Library()


Gelen veriyi geri döndüren basit bir etiket oluşturduk. Ardından register değişkenini kullanarak etiketi kaydettik. register değişkenine Library sınıfını atamıştık. simple_tag Library sınıfının bir fonksiyonudur.

def beniyaz(veri):
return veri
register.simple_tag(beniyaz)


Daha gelişmiş bir etiket oluşturduk ve bunu register.tag ile (tag Library sınıfının bir fonksiyonudur) kaydettik. islem fonksiyonu içerisinde ise nodelist değişkenine etiketin ilk ve son kısımları arasındaki içeriği aldık. Etiketimizin bitiş kısmını burada islembitti değeri ile belirledik. Yani {% islem %} ... {% islembitti %} arasındaki içerik bu etiketin alanı olacak. bits değişkenine de etiket açılışında tanımlanan verileri aktardık ( örn: {% etiket_adi veri1 veri2 ...% } deki veri1, veri2 vb. değerleri). Ardından bu değişkenleri(nodelist,bits), işlenip geri dönmesi için IslemNode sınıfına aktardık.

def islem(parser,token):
nodelist = parser.parse(('islembitti',))
parser.delete_first_token()
bits = token.contents.split(' ')
return IslemNode(nodelist,bits)
register.tag(islem)


Eğer oluşturmuş olduğumuz islem etiketi şablon dosyasında kullanılırsa, bu etiketin yorumlanması sırasında IslemNode sınıfı içerisindeki render fonksiyonu devreye girecektir. Bu fonksiyon devreye girdiğinde, önce {% islem %} {% islembitti %} arasındaki verileri yorumlayacak, ardından bunu icerik değişkenine aktaracak. islem etiketi ile gelen verilere göre(bits) kontrol yapılıp geriye sonucu döndürecektir.

Tabi bu bizim aşağıdaki sınıf için geçerli. Siz render fonksiyonu içerisinde kendi etiketinize göre işlemleri yaptırmalısınız. Bilmeniz gereken render fonksiyonu içerisinde bulunan self.nodelist.render(context) ile etiketinizin içeriğinin görüntülenebilir halini alabilmenizdir.

class IslemNode(Node):
def __init__(self,nodelist,bits):
self.nodelist = nodelist
self.bits = bits

def render(self,context):
icerik = self.nodelist.render(context)
sonuc = eval(icerik)
if self.bits.__len__()>1:
if self.bits[1] == 'sadece_sonuc':
return sonuc
return u"Yapılan İşlem %s : %s" %(icerik,sonuc)


Index.html Dosyası

Yazdığımız ozeletiketler.py dosyamızı şablon dosyası içerisine dahil ettik. Böylelikle bu dosya içerisindeki özel etiketleri kullanabildik. Buradaki ozeletiketler dosyamızın ismidir. templatetags içerisinde dosyaları herhangi bir isimde oluşturabilirsiniz. load ile kullanım sırasında ise oluşturduğunuz dosya ismini belirtmelisiniz.

{% load ozeletiketler %}


beniyaz isimli etikete bir değer vererek, değeri ekrana yazdırdık.

{% beniyaz "merhaba dünya" %}


İşlemin, açıklamalı olarak ekrana yazdırılmasını sağladık.

{% islem %} 20 + 5 {% islembitti %}


İşlemin sadece sonucunun ekrana yazdırılmasını sağladık.

{% islem sadece_sonuc %} 11 - 4 {% islembitti %}


Açıklamalar belki kafa karıştırıcı olabilir. Bunu en aza indirmeye çalıştım. Aklınıza bir kaç soru gelebilir. Belki bunları tahmin edebilirim düşüncesiyle kendi kendime bir kaç soru sorup cevaplarını vermeye çalışacağım.

1 - Etiket isimlerini nasıl belirliyoruz?
Etiket ismi, özel etiket dosyanızda belirlediğiniz fonksiyon ismidir. Eğer farklı bir isim kullanmak isterseniz register.tag fonksiyonunu aşağıdaki gibi kullanmalısınız. register.simple_tag için böyle bir özellik bulunmuyor.


register.tag("yeni_etiket_adi",fonksiyon_adi)


2 - Etiket açılışında tanımlanan verileri ayırma işlemini ne şekilde yapabilirim?

Bu işlemi token.contents.split(' ') bölümünden gerçekleştirebilirsiniz. Örneğin boşluk yerine tırnak ile verileri ayırmak isteyebilirsiniz. Bunun için aşağıdaki gibi bir kullanım işinizi görecektir.


def islem(parser,token):
[...]
bits = token.contents.split('\"')
[...]



[...]
{% islem "sadece_sonuc" ... %}
[...]


3 - Daha fazlası için?

django/template/defaulttags.py dosyasını inceleyebilirsiniz.

29 Eylül 2008 Pazartesi

Django ile Anket 3

Bundan önceki uygulamarımızda anket oluşturmak, düzenlemek ve yeni seçenekler eklemek gibi bir takım ayarları yapmayı öğrenmiştik. Ama bunları sadece admin paneli üzerinden yapıyorduk. Peki bu anketleri nasıl sayfamızda gösterebiliriz ?

Anketleri sayfamızda gösterebilmemiz için anket uygulaması içerisinde yer alan view.py dosyasında bir takım düzenlemeler yapmamız gerekiyor. View.py dosyasının içeriğini şu hale getirelim.

from django.template import Context, loader
from OrnekProje.anket.models import Anket
from django.http import HttpResponse
from django.shortcuts import render_to_response, get_object_or_404

def index(request):
son_anketler = Anket.objects.all().order_by('-yayin_tarihi')[:5]
return render_to_response('anket/index.html',{'son_anketler':son_anketler })

def detail(request, anket_id):
p = get_object_or_404(Anket, pk=anket_id)
return render_to_response('anket/detail.html', {'anket': p})

def all(request):
anketler = Anket.objects.all().order_by('-yayin_tarihi')
return render_to_response('anket/all.html',{'anketler':anketler})

Ardından urls.py dosyanını şu şekilde düzenleyin. Bu arada yukarıda ki kodlar için acele etmeyin hepsini açıklayacağım ;)

urlpatterns = patterns('',
(r'^admin/(.*)', admin.site.root),
(r'^anket/$', 'OrnekProje.anket.views.index'), #[1]
(r'^anket/(?P\d+)/$','OrnekProje.anket.views.detail'),
(r'^anket/all/$','OrnekProje.anket.views.all'),


Öncelikle urls.py dosyasından başlayalım. #[1] ile biten satıra bakalım. Bu satırda djangoya /anket/ adresine gelen bir istek olursa OrnekProje/anket/views dosyasından index fonksiyonun çalıştırılması isteniyor. ( url tanımı yapılırken kullanılan düzenli ifadelerden gökmen ve mirat daha önceki yazılarında bahsettikleri için uzun uzun değinmiyorum.) Şimdi gelelim index fonksiyonuna. İlk satırda son_anketler isimli değişkene veri tabanındaki son 5 anketi tarih sırasına göre atıyoruz. 2. satırda ise render_to_response nesnesini kullanarak
anket dizini içerisindeki index.html dosyanı son_anketler ile verilen değerleri kullanarak bir değer döndürmesini istiyoruz. (Sanki biraz karışık bir cümle oldu :/)

Ama sanki bir şey unuttuk ? anket/index.html diye bir dizin ve dosya yaratmadık. Şimdi OrnekProje dizini içerisinde Templates diye bir dizin oluşturalım. Burada tüm templatelerimizi saklayalım. İyi bir gruplandırma olması açısından her uygulama için ayrı bir dizin kullanalım. Yani onunda içerisinde bir anket dizini oluşturalım.

Bu dizinleri oluşturduktan sonra bunlardan djangoyu haberdar etmeye geldi sıra. Bunun için settings.py dosyasındaki TEMPLATE_DIRS satırını şu şekilde değiştirmemiz gerekiyor.

TEMPLATE_DIRS = ("/home/Deniz/OrnekProje/templates" # dizini kendi dizininizle değiştirmeri unutmayın :)
)


Şimdi tekrar templates/anket klasörüne gidip index.html dosyasını oluşturup içeriğini şu şekilde dolduralım.

{% if son_anketler %}
<ul>
{% for anket in son_anketler %}
<li>{{ anket.soru }}</li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}



İlk satırda ki if sorgusu ile eğer son_anketler değeri var ise aşağıdaki işlemleri yapmasını söylüyoruz.

for döngüsü ise anket olduğu sürece anket sorularını ekrana bastırmamıza yarıyor.

Eğer if sorgusu False değeri döndürürse (yani hiç anket yoksa) else bloğu işletiliyor.

Burada sadece anket sorularını ekrana yazdırdık.

Şimdi urls.py dosyamızın 2. satırını ve detail fonksiyonunu açıklayalım. 2. satırda "/anket/2" "/anket/3" gibi sayfalara gelen isteklerde anket numarasına göre o anketi kullanmamızı için anket_id değerini parametre olarak detail fonksiyonuna gönderiyor.


def detail(request, anket_id):
p = get_object_or_404(Anket, pk=anket_id)
return render_to_response('anket/detail.html', {'anket': p})


Burda da farklı olarak get_object_or_404 nesnesini kullandık. Bu nesne eğer anket_id değeri ile gelen bir değer yoksa ekrana sayfa bulunamadı yazdırmamızı sağlıyor.

Bu da detail.html dosyamızın içeriği

<h1>{{ anket.soru }}</h1>
<ul>
{% for secim in anket.secim_set.all %}
<li>{{ secim.secenek }}</li>
{% endfor %}
</ul>


Burada 3 numaralı anketimizi görüntüledik.

Son fonksiyomuz olan all ve urls.py dosyasındaki ona ait olan satırı uzun uzun anlatmayacağım. Önceki bilgilerimiz ile neyin ne olduğunu anlayabiliriz :) Burada da tüm anketlerimizi ve şıklarını aynı anda sayfaya yazdırıyoruz.

all.html dosyasının içeriği;


{% for anket in anketler %}
<h3> {{anket.soru}} </h3>
{% for secim in anket.secim_set.all %}
<li> {{secim.secenek}} </li>
{% endfor %}
{% endfor %}




Yine template dosyaları aracılığıyla bu yazdıklarımızı özelleştirmek sizin elinizde ;)

25 Eylül 2008 Perşembe

Django ile Anket 2

Kaldığımız yerden devam edelim. Şimdi admin panelini kullanarak iki anket ekleyin.
Ben anket sorusu olarak "Hangi editörü kullanıyorsunuz ? " ve "Günde kaç saat bilgisayar başındasınız ?"'ı ekledim.
Ardından anasayfadan Anket bölümüne tekrar geldiğinizde eklediğimiz anketlerin listelendiğini göreceksiniz.

Sanırım hepiniz tuhaf giden birşeyler olduğunu fark etmişsinizdir. Tüm anketler "Anket object" ismiyle yani ne olduğunu anlayamadığımız bir isimle listelenmekte. Gelin bunu rahat anlaşılabilir bir hale nasıl sokabiliriz onu inceleyelim.

Bunun için models.py dosyamızdaki sınıflarımızın altına şu satırları ekliyoruz.

def __unicode__(self):
return self.soru


Bunu anket sınıfının altına ekliyoruz. Burada verdiğimiz self.soru veritabanında ki kaydımızın ismi.


def __unicode__(self):
return self.secim

Bunu da Secim sınıfına ekliyoruz.

Şimdi admin panelini güncelleyip nasıl göründüğüne bir bakalım. Sanırım bu hali daha açıklayıcı olmuştur ;)

Şimdi de alanların yerlerini değiştirelim. Şu anda bir anket eklerken ilk sırada soru 2. sırada da yayin tarihi bulunuyor. Şimdi bunların yerlerini değiştirelim. Anket dizini içerisindeki admin.py dosyasında admin.site.register() yerine aşağıdaki satırları ekleyin.

class AnketAdmin(admin.ModelAdmin):
fields = ['yayin_tarihi','soru']

admin.site.register(Anket,AnketAdmin)

Değiştirdikte ne oldu yani şimdi ? dediğinizi duyar gibi oluyorum :) Anket uygulaması gibi 2 alandan oluşan bir uygulamada pek bir işe yaramaz ama alan sayısı arttıkça sıralamanın istediğini gibi olmasını isteyebilirsiniz. Ya da sık kullanılmayan bazı alanları gizlemek ya da benzer kategorileri gruplandırmak. Şimdi bunlara da birer örnek verelim. İhtiyacınız olduğunda bu da varmış diye aklınızda bulunsun ;) Yine admin.py dosyasında ki AnketAdmin clasını değiştiriyoruz.

class AnketAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['soru']}),
('Tarih Bilgileri', {'fields': ['yayin_tarihi']}),
]

Bu değişiklikle Yayin Tarihi bilgileri ayrı bir bölümde Tarih Bilgileri başlığıyla gösterilecek. Tarayıcımıza gidip hemen bir kontrol edelim.

Ardından da ufak bir değişiklik daha yapalım.

class AnketAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['soru']}),
('Tarih Bilgileri', {'fields': ['yayin_tarihi'],'classes': ['collapse']}),
]


Neyse bu kadar ince ayar yeter. Biz anketimize geri dönelim. Anketi hazırladık fakat sorular yok. Hemen sorularıda admin paneline tanıtalım. Bunun nasıl yapıldığını daha önce görmüştük. admin.py dosyasını açıyoruz tekrar.

admin.site.register(Secim)

Satırını ekliyoruz.

Ardından Secimleri seçip bir kaç seçenek ekleyelim ki anketimiz şenlensin ;)
Yeni seçenek eklerken yukarıdan hangi ankete ekleyeceğimiz seçiyoruz. Fakat önce soruyu ekle sonra seçenekleri ekle falan bana pek kullanışlı gelmiyor. Eğer sizde benim gibi düşünüyorsanız birde şunu deneyin.

Az önce eklediğimiz satırı kaldırıp AnketAdmin sınıfının sonuna inlines = [Secimler] i ekliyoruz. Yani dosyamızın son hali şuna benzeyecek.

from OrnekProje.anket.models import Anket
from OrnekProje.anket.models import Secim
from django.contrib import admin


class Secimler(admin.StackedInline):
model = Secim
extra = 4

class AnketAdmin(admin.ModelAdmin):
fieldsets = [
(None, {'fields': ['soru']}),
('Tarih Bilgileri', {'fields': ['yayin_tarihi'],'classes': ['collapse']}),
]
inlines = [Secimler]

admin.site.register(Anket,AnketAdmin)

Yeniden bir kayıt girmeyi deneyin ya da girdiğiniz kayıtları düzenleyin.
Birde Secimler(admin.StackedInline) yerine admin.TabularInline şeklinde kaydedip deneyin. Hangisi daha hoş ?

Ekleme bölümünü baya bir kurcaladık. Sıra geldi değişiklik bölümüne, Anketler-Değiştire geldiğinizde sadece anketin ismini görebiliyorsunuz. Şimdi biraz daha ayrıntı ekleyelim. inlines seçeneğinde yaptığımız gibi bir değişiklik yapacağız. admin.py dosyasında AnketAdmin sınıfı altına şu satırı ekleyelim.

list_display = ('soru','yayin_tarihi')

Şimdi sayfamızı yenileyelim. Ardından az önceki örnekte olduğu gibi aşağıdaki satırlarıda tek tek(!) ekleyerek her birinin neler yaptığını anlamaya çalışın.

list_filter = ['yayin_tarihi']
search_fields= ['soru']
date_hierarchy = 'yayin_tarihi'

23 Eylül 2008 Salı

Django ile Anket

Bu uygulamamızın temel amacı django ile admin panelini anlatmak olacak. O yüzden onun dışında kalan bölümleri hızlıca geçeceğim.O bölümler daha önce gökmen ve mirat tarafından ayrıntılı olarak anlatılmıştı. Eğer başlangıçtaki bazı örnekleri anlayamazsanız daha önce yazılmış django notlarından faydalanabilirsiniz.

Şimdi yeni bir proje başlatmak için gerekli olan komutumuzu veriyoruz.

Deniz@ParMak ~ $ django-admin.py startproject OrnekProje

OrnekProje adıyla yeni bir projeye başladık şimdi o dizine geçip uygulamamıza devam edelim.

Deniz@ParMak ~ $ cd OrnekProje/


Şimdi de projemiz içerisinde yeni bir uygulama başlatalım.
Not: Uygulamalar genellikle belirlir bir görevi yerine getirmek üzere kullanılırken. Projeyi ise içinde bir çok uygulamayı içerisinde düzenli şekilde barındıran uygulamalar bütünü olarak tanımlayabiliriz. Yine uygulamalarımızı bir kere oluşturup farklı projeler içerisinde de kullabiliriz.

Deniz@ParMak OrnekProje $ python manage.py startapp anket

Projemiz içerisinde anket isimli bir dizin oluştuğunu göreceksiniz içinde ise "__init__.py __init__.pyo models.py models.pyo views.py views.pyo " dosyaları mevcuttur.

models.py dosyası bizim modellerimizi tanımlayacağımız dosya olacak. Anket uygulaması için 2 model oluşturacağız: Anket ve Secim. Anket içerisinde soru ve yayın tarihi yer alırken Secim içerisinde secenekler ve oylar alanları yer alacak. Bunun için aşağıda ki kodları models.py dosyamıza kaydediyoruz.

from django.db import models

class Anket(models.Model):
soru = models.CharField(max_length=200)
yayin_tarihi = models.DateTimeField('yayin tarihi')

class Secim(models.Model):
anket = models.ForeignKey(Anket)
secenek = models.CharField(max_length=200)
oylar = models.IntegerField()


Şimdide bir üst dizinde yer alan settings.py dosyasında INSTALLED_APPS kısmını şu şekilde düzenliyoruz.


INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'OrnekProje.anket',
)


Şimdi veri tabanı ayarlarını düzenliyoruz. (Ayrıntılı bilgi için miratın yazını inceleyiniz.


DATABASE_ENGINE = 'mysql' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = 'veritabanı_ismi' # Or path to database file if using sqlite3.
DATABASE_USER = 'Deniz' # Not used with sqlite3.
DATABASE_PASSWORD = 'şifrem' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.

Eğer Pardus kullanıyorsanız Tasma-Servis Yöneticisinden mysql_server'i çalıştırmayı unutmayınız.

Ardından bakalım az önce models.py içerisine pythoncasını yazdığımız modellerin mysql karşılıkları nelermiş ?

Deniz@ParMak OrnekProje $ python manage.py sql anket
BEGIN;
CREATE TABLE `anket_anket` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`soru` varchar(200) NOT NULL,
`yayin_tarihi` datetime NOT NULL
)
;
CREATE TABLE `anket_secim` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`anket_id` integer NOT NULL,
`secenek` varchar(200) NOT NULL,
`oylar` integer NOT NULL
)
;
ALTER TABLE `anket_secim` ADD CONSTRAINT anket_id_refs_id_4e3e5fcb FOREIGN KEY (`anket_id`) REFERENCES `anket_anket` (`id`);
COMMIT;


Eğer benzer bir çıktı aldıysanız herşey yolunda devam edebiliriz.
Eğer bir hata almadıysanız djangoya az önceki sql komutlarını çalıştırmasını söylemek için aşağıda ki komutu giriyoruz.

python manage.py syncdb

Çıktısında şöyle birşey göreceksiniz.

Creating table anket_anket
Creating table anket_secim
Installing index for anket.Secim model

Şu ana kadar veri tabanı ayarlarımız yaptık şimdi Admin paneliyle ilgili ayarlarımıza geçiyorum.

Tekrar setting.py dosyasını açıp INSTALLED_APPS bölümüne az önceki örnekteki gibi 'django.contrib.admin' satırını ekliyoruz.

Ardından tekrar python "manage.py syncdb" komutunu verip veri tabanını güncellemesini istiyoruz. Bu esnada sizden admin paneline girişte kullanmanız için bir kullanıcı adı ve şifresi isteyecek gerekli ayarları yapıp devam ediniz.

Son olarakta urls.py dosyasının başında admin paneli için gerekli olan modülleri yüklemek için # işaretini kaldırıyoruz. Ve yine o dosyanın sonundaki admin alanını djangoya göstermek için oradan da # işaretini kaldırıyoruz.
Yani dosyanın en son hali şu şekilde olacak.

from django.conf.urls.defaults import *

# Uncomment the next two lines to enable the admin:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
# Example:
# (r'^OrnekProje/', include('OrnekProje.foo.urls')),

# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),

# Uncomment the next line to enable the admin:
(r'^admin/(.*)', admin.site.root), #burasını
)

Şimdi django sunucusunu çalıştıralım.

python manage.py runserver

Şimdi tarayıcınızdan http://127.0.0.1:8000/admin/ adresini açıp neler olduğuna bakabilirsiniz :)

Biraz kurcalayınca Gruplar,Kullanıcılar ve Siteler adında 3 bölüm göreceksiniz. Bunlar django ile öntanımlı olarak gelen admin paneli araçlarıdır. Fakat sanki bizim anket piyasada görünmüyor ? Bunun için yapmamız gereken tek birşey daha kaldı. Anket dizini içerisine admin.py adında bir dosya oluşturup içerisine şu satırları eklemek.

from OrnekProje.anket.models import Anket
from django.contrib import admin

admin.site.register(Anket)


Şimdi sunucumuzu yeniden başlatalım.(Ctrl+c) ile sonlandırıp. python manage.py runserver ile yeniden başlatabilirsiniz.

Eğer bir aksilik çıkmadıysa artık admin panelinde anket uygulamımızı görmüşsünüzdür. Aslında buradan sonra anlatılacak pek birşey kalmıyor ama ben kısaca bir kaç ufak şeyden bahsedeyim.

*Anketlere girdiğimizde görmüş olduğumuz form anket modelinde yazmış olduğumuz koda göre django tarafından otomatik olarak oluşturuluyor.

*Anket modelinde oluşturduğumuz alanları hatırlayacak olursanız (DateTimeField, CharField gibi) django bunlara bakarak admin panelinde ona göre bir html üretiyor.

*Örneğin DateTimeField ile gün ayarı yapabileceğimiz bir JavaScript kısayolunu bizim için panele ekliyor.

Şimdilik bu kadarla kesiyorum. Admin panelinide kendi isteğimize göre özelleştirebiliyoruz. İlerleyen günlerde bu ufak tefek özelleştirmelerden de bahsedebilirim.

19 Eylül 2008 Cuma

Ev Yapımı Şifreleme

Merhaba.
Bugün size Python ile ev yapımı şifreleme nasıl yapılır ondan bahsedeceğim. Ev yapımı şifrelemeden neyi kastettiğimi yazının devamında daha rahat anlayacaksınız.
(Not: Yazar girişte başlığı kullanarak merak uyandırmaya çalışmış ve okuyucuyu yazının devamını okuması için teşvik etmeye çalışmıştır).

Programı görmeden önce size bu programı nerede kullanabileceğinizden bahsedeceğim, programın bu bilgiyle incelendiğinde daha kolay anlaşılacağını düşünüyorum.

Senaryomuz şöyle;

Bir uygulama geliştirdiniz. Uygulamanız kullanıcı adı ve şifre girişi gerektirmekte ve sizde bu kullanıcı adını ve şifreyi kullanıcının bilgisayarında tutmak durumundasınız. Sadece bir kullanıcının kullanıcı adı ve şifresini tutmak içinde veritabanı kullanmak istemiyorsunuz. Bu durumda bu bilgileri bir dosyada tutmanız gerek. Buraya kadar her şey normal. Sorun bu bilgileri o dosyada nasıl tutacağınız. Bir dosya oluşturup içerisine pattadanak (böylemi yazılıyor bu?) yazacak değilsiniz. Bu kadarla da kalmıyorsunuz programınız kullanıcınızın izni dışında 3. şahıslar tarafından kopyalandığında da o 3. şahıs programını çaldığı kullanıcınızın bilgileri ile giriş yapamasın istiyorsunuz, yok artık!!! İşte bu yazıda böyle bir ihtiyaç durumunda kullanabileceğiniz bir şifreleme yönteminden, kendi verdiğim isimle "Ev Yapımı Şifreleme" den bahsedeceğim.

Çok konuştuk, kodu görelim. Önce kodun tamamını verip daha sonra parça parça açıklamasını vereceğim.

import operator
import sys,os

class Encrypt():
def xor(self, password,encrypt=True):
key=self.mix_mac()
if not encrypt:
key+='\x00'
p_sira = -1
encrypted = ""
for str_sira in range(len(key)):
p_sira += 1
if (p_sira >= len(password)): p_sira = 0
p = str(password[p_sira])
s = str(key[str_sira])
e = chr ( operator.xor(ord(s), ord(p)))
encrypted += e
if encrypt:
encrypted += str(len(password))
return encrypted

def decrypt(self,enc):
enc_len=int(enc[len(enc)-1])
return enc[:enc_len]

def mix_mac(self):
mac=self.getMacAddress()
KEY='pythontr'
mixed_mac=''
str_mac=str(mac)

for i in range(len(KEY)):
mixed_mac+=str_mac[i]+KEY[i]
mixed_mac+=str_mac[len(KEY):]
return mixed_mac

def getMacAddress(self):
if sys.platform == 'win32':
for line in os.popen("ipconfig /all"):
if line.lstrip().startswith('Physical Address'):
mac = line.split(':')[1].strip().replace('-',':')
break
else:
for line in os.popen("/sbin/ifconfig"):
if line.find('Ether') > -1:
mac = line.split()[4]
break
return mac


Eveet, şimdi gelelim açıklama kısmına. Önce programın tam olarak ne yaptığını anlatayım daha sonra açıklamalara geçeriz. Program kullanıcının mac adresini sizin verdiğiniz KEY ile (burada "pythontr") bit kaydırma işlemine tabi tutup bir değişken üretiyor. Daha sonra sizin verdiğiniz değişken ile (şifrelenecek değişken) kendi ürettiği değişkeni xor işlemine sokup size şifrelenmiş veriyi döndürüyor.

Gelelim metodlara:

getMacAddress():

os ve sys modüllerini kullanarak kullanıcının mac adresini öğreniyoruz.

sys.platform ile kullanıcının işletim sistemini öğreniyoruz, burada winfos ve linux için düzenlenmiştir.

os.popen ile komut istemine bir boru açıp mac adres bilgilerini veren komutu çalıştırıyoruz, devamında ise string işlemlerle çıktıdan mac adresini ayıklıyoruz.

mixMac():

Burada aldığımız mac adresi ile belirlediğimiz KEY değişkenini bit kaydırma işlemi ile karıştırıyoruz ve bu karıştırdığımız yeni string veriyi döndürüyoruz. Burada dikkat edilecek önemli nokta verdiğiniz KEY'in mac adresinden uzun olmaması gerektiği. Aksi halde "string index out of bound" hatası alırsınız.

decrypt():

Bu fonksiyon ise şifresini çözdüğümüz veriden ham şifreyi elde etmeye yarıyor. Programın kullanımında da göreceğiz, 8 karakterli bir şifre verdiğinizi varsayalım, çözdüğünüz şifre mac adresinin karakter sayısı+verdiğiniz KEY'in karakter sayısı kadar tekrarlı gelecek. Bu yüzden şifreleme yaparken şifreli verinin sonuna şifrenin karakter sayısını giriyoruz ve bu fonksiyonda o karakter sayısı kadar veriyi çekip tekrarları almamış oluyoruz. Korkmayın aşağıda örnekleyince daha kolay anlayacaksınız :)

xor():

Esas oğlan. Şifreleme işlemini yapan fonksiyon. Yaptığı iş çok karışık değil aslında. Programa gönderdiğiniz şifre ile programın oluşturduğu verinin her bir karakterinin ASCII kodunu alıp onları xor işlemine sokuyor. Burada "encrypt" parametresinden bahsetmekte fayda var. Şifreleme yapacağımız zaman "True" çözümleme yapacağımız zaman "False" değeri veriyoruz. Onu şu sebepten kullandık, şifreleme sırasında şifrelediğimiz verinin karakter sayısını verinin sonuna eklediğimizi söylemiştik. Çözümleme yaparken referansımız olan mac adresi ile xor işlemine soktuğumuzda verideki karakter sayısının işlenmediğini görürüz, çünkü mac adresinin karakter sayısı aynıdır ancak biz şifreli veriye sonradan bir karakter eklemişizdir, dolayısıyla mac adresinde o karakter ile xor işlemine girecek eleman kalmamıştır. Bu yüzden çözümleme yapacağımız zaman mac adresine şifremizin eleman sayısını da işleme sokmak için bir veri ekliyoruz. Peki nedir eklediğimiz veri "\x00" verisi, yani ascii 0'ın char karşılığı. Peki neden 0 ekledik, 0 ile herhangi bir sayıyı xor işlemine sokarsanız sonuç olarak sayının kendisini alırsınız. Anlayacağınız 0 xor işlemi için etkisiz eleman, dolayısıyla bize direk olarak şifremizin karakter sayısını döndürüyor. Olay bundan ibaret, 2 tane integer değerin xor sonucunu veriyor bize (her karakter için). Şifrelenmiş verimiz bu oluyor.

Şimdi gelelim programın örnek kullanımına. Python yorumlayıcısını açıyoruz (yanında kahve içmekte özgürsünüz) ve başlıyoruz.


In [1]: from Encrypt import Encrypt
In [2]: e=Encrypt()
In [3]: passwd='adige'
In [4]: sifreli=e.xor(passwd)
In [5]: sifreli

Out[1]: 'Q\x14SUW[!-]]%T\x10]WS^,#_Y S\x13_SVS"![\\-W\r[V[] %^Q#&\x0e^[U_$ S_![\nSUW[!-]]%!\x1d]WS^,#_Y Z\x15_SVS"![\\-5'

In [6]: sifresiz=e.xor(sifreli,False)
In [7]: sifresiz

Out[2]: 'adigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadigeadi5'

In [8]: sifre=e.decrypt(sifresiz)
In [9]: sifre

Out[3]: 'adige'


Programın kullanımı bu şekilde. Kafanıza takılan bişey olursa sormaktan çekinmeyin.
Şimdilik benden bu kadar, bir sonraki Python macerasında görüşmek üzere.

Özgür kalın..

Django Notları - 5 (Veritabanı Kullanımına Genel Bakış)

Artık bir django uygulaması yaratmanın vakti geldi.

python manage.py startapp rehber

Gördüğünüz komut projenizin bulunduğu klasör içerisine "rehber" adlı bir dizin oluşturacak ve dizin yapısını incelerseniz models.py ve views.py dosyalarını görebilirsiniz.

Işık yandı mı?

Kullanıcı sizin sitenize rehber dizini altına girdiğinde (adres çubuğuna www.siteniz.com/rehber yazıp enter tuşuna bastığında) rehber adlı uygulamaya giriş yapmış oluyor. Rehber uygulaması kendi içerisinde sergileme ,veri yönetimi modüllüllerini kısacası rehber uygulamanızda kullanacağınız herşeyi barındırıyor. Böylelikle proje geliştirirken ayrı ayrı geliştirdiğiniz uygulamaları birbirinden bağımsız olarak çalışabiliyorlar. Örneğin daha önce geliştirdiğiniz forum uygulamasını yeni projenize entegre etmek bir klasör kopyalamak ve setting.py içerisine bir satır eklemek kadar kolay oluyor.

Yalnız dikkat etmemiz gereken önemli bir nokta var biz burada uygulama oluştururken keyfi davranmadık. Çünkü Django'da veritabanı modellerinin bir uygulama içerisinde bulundurulması gerekiyor.

Şimdi yarattığımız uygulamayı projeniz içerisine yerleştirmemiz gerekli. settings.py dosyası içeriside INSTALLED_APPS adlı bir tüp (tuple) göreceksiniz. Gördüğünüz gibi projemiz şu anda kullanmayacağımız birkaç uygulama barındırıyor. Bunların başına yorum işareti koyarak (#) iptal edelim ve rehber uygulamamızı tüp içerisinde belirtelim. Yalnız burada dikkat etmemiz gereken birşey var Python da tek elemanlı bir tüp belirtiyorsak elemanımızın yanına bir adet , koymayı unutmamalıyız. Çünkü eğer virgül koymazsak python bunu gruplama işareti olarak algılıyor.

tek_elemanli_tup = ('eleman',)

bizim de INSTALLED_APPS'ımız şı şekilde olacak:

INSTALLED_APPS = (
# 'django.contrib.auth',
# 'django.contrib.contenttypes',
# 'django.contrib.sessions',
# 'django.contrib.sites',
'mysite.rehber',
)


İlk Modelimiz



Şimdi bir uygulama oluşturmuş ve bunu projemiz içine yerleştirmiş bulunmaktayız. Veritabanı ile oynaşmaya başlayabiliriz. mysite/rehber içerisindeki models.py dosyasını düzenlemek üzere açın. Aşağıdaki hale getirin.

from django.db import models

# Create your models here.

class rehber(models.Model):
firstname = models.CharField(max_length = "20")
surname = models.CharField(max_length = "20")
phone = models.CharField(max_length = "14")


İşte bitti ... models.Model sınıfının mirascısı olarak yarattığımız model; atasından veritabanı ile ilgili bütün mekanizmayı miras alıyor. Bu sebepten (yerel veri tabanına senkronize edildikten sonra) kullanılmaya hazır halde.

Veri modellerimizi veri tabanına senkronize etmeden önce herhangi bir soruna oluşmasına karşı onaylatmamız gerek. Bu işlem zorunlu değil ama yinede yapsanız iyi olur.

mysite $ python manage.py validate
0 errors found.


Tamam herşey güzel gözüküyor kazasız belasız modelimizi oluşturmuşuz.. o zaman hadi veritabanımız ile senkronize edelim.

mysite $ python manage.py syncdb
Loading 'initial_data' fixtures...
No fixtures found.


Bu komut size farklı cevaplar verebilir (ben veri tabanı olarak sqlite3 kullanıyorum.) ama error demiyorsa sorun yok demektir. Veritabanımız, modellerimiz oluşturuldu ve senkronize edildi. Şimdi yapabileceğimiz işlemleri uygulamalı olarak ele alalım. Bunun için etkileşimli kabuğu kullanacağız.

mysite $ python manage.py shell

Bu bize bizim projemizdeki ayarlarımızla yüklenmiş bir kabuk açacaktır.

Kayıt Eklemek ve Güncellemek



In [1]: from mysite.rehber.models import rehber

In [2]: people = rehber(firstname='Mirat',surname='bayrak',phone='123 23 23')

In [3]: people.save()


Gördüğünüz ilk satırda projemiz altındaki rehber uygulaması içerisindeki modellerden rehber modelini import ettik. Daha önce söylediğim gibi bu model tek başına veri tabanı işlemleri için gerekli bütün mekanizmayı içeriyor.

2. satırda bir rehber örneği oluşturduk.

3. satırda kaydettik!!

Kayıtları Listelemek



In [4]: print rehber.objects.all()
[]


rehber.nesnelerinin.hepsi() gibi harika bir cümle yapısıyla veri tabanımızdaki bütün kayıtları getirdik (henüz 1 tane var) fakat birşey eksik sanki? print komutu bize bir Python veri sınıfı olarak gösterdi nesnemizi.. neden oldu bu? çünkü modelimiz kendisini nasıl karakter katarı olarak sergileyeceğini bilmiyor (string presentation).

Modele davranış kazandırmak



Şimdi ctrl+d kombinasyonu ile kabuktan çıkın. Tekrar rehber uygulaması içerisindeki models.py dosyasını açın ve onu şu hale getirin.

class rehber(models.Model):
firstname = models.CharField(maxlength=30)
surname = models.CharField(maxlength=30)
phone = models.CharField(maxlength=14)
def __str__(self):
return "name : %s , surname : %s , phone : %s" % (self.firstname,self.surname,self.phone)


Burada ne yaptık? __str__ fonksiyonu tanımlayarak modelimize kendisini nasıl metin olarak sergileyeceğini öğrettik.

Önemli not : Django 1.0 ile birlikte __str__() yerine __unicode__() fonksiyonunun kullanılması öneriliyor.

Şimdi tekrar kabuğa dönüp kayıtlarımızı listeletmeye çalışalım.

In [1]: from mysite.rehber.models import rehber

In [2]: print rehber.objects.all()

[

Veriyi Güncellemek



Eğer yukarıda geçen kaydetme kısmında verdiğimiz kodda people örneğinin içindeki herhangi bir alanı değiştirip tekrar kaydetseydik. Bu yeni bir kayıt olarak geçmeyecek, veritabanındaki aynı kayıt güncellenecekti.

In [1]: from mysite.rehber.models import rehber

In [2]: people = rehber(firstname='Mirat',surname='Çaylak',phone='123 23 23') # örnek oluştur

In [3]: people.save() # kaydet

In [4]: rehber.objects.all() # bütün veri tabanını getir

Out[4]: []

In [5]: people.surname = "kamil" # örnepğin surname alanını değiştir

In [6]: people.save() # tekrar kaydet

In [7]: rehber.objects.all() # yeni kayıt oluşmadı, olan değiştirildi.

Out[7]: []


Filitrelemek



Sadece belli kriterlere sahip veriyi çekmek istediğimizde ,örneğin sadece firstname alanı "Mirat" olan kayıtları getirmek için...

In [9]: rehber.objects.get(firstname='Mirat')
Out[9]:


"Mi" hecesiyle başlayan kayıtları listelemek için :

>> print Entry.objects.filter(firstname__startswith="Mi")

İçinde "rat" hecesi geçen kayıtları aramak için..

>> print Entry.objects.filter(firstname__contains="rat"),

Sıralamak



Genelde veritabanından çektiğimiz veriyi belli bir sıralamaya göre sergilemek isteriz. Örneğin forumlarda her giriş (entry) tarihsel olarak yeniden eskiye doğru sıralanırlar. Biraz önce veritabanından nasıl veri alacağımızı görmüştük sıralama işlemi ise gayet kolay.

isme göre sıralayarak bütün verileri getir :

>>> rehber.objects.order_by("firstname")

kolay değilmi?

hem filitreleme hemde sıralama uygulamak istediğimizde:

>>> rehber.objects.filter(firstname__contains = "rat").order_by("name")

harika... :) eğer order_by("-name") deseydik sıralamayı tersine çevirecekti.

Parça Almak



Örneğin bütün rehberinizi isim,numara şeklinde değil, sadece numaraları almak istiyorsanız.

>>> rehber.objects.all()[0]

şeklinde o tabloya bir listeymiş gibi davranabilirsiniz.

Bittimi? bitmedi... bir dahaki yazımızda görüşmek üzere...