dün gece django 1.2 stable sürümü duyuruldu. django 1.2 ile birlikte benim gözüme çarpan önemli yenilikler;
multiple database desteği
tek proje içinde birden fazla veritabanı kullanmak artık “hacky” bir yönteme başvurmadan mümkün. settings.py içinde ayarlıyorsunuz o kadar.
model validation desteği
artık ilgili objenin bağlı bulunduğu modele göre otomatik validation yapabiliyoruz.
messages framework
(bu özellik için svn versiyonunu kullanıyordum) messages framework, kullanıcılara tek seferlik görünen hata/bilgi/başarı mesajları göstermenizi sağlayan bir çatı. daha önce django-flashmessages gibi eklentiler vardı bu iş için, ama çekirdeğe böyle bir özellik gelmesi harika oldu. messages.error(request, “hata mesajı”) formatında kullanıcı oturumuna ait hata ekleyebiliyorsunuz mesela.
template etiketlerinde akıllı kontroller
ifequal gibi zorlama bir tag yerine, -sonunda!- artık, template dosyalarında statement’lar kullanabilir durumda. şöyle ki;
{% ifequal request.user.username related_profile.username %}
yerine
{% if request.user.username == related_profile.username %}
kullanabiliyoruz. yaşayanlar bilir, çok can sıkıcıydı bu durum.
bunların dışında “template caching”, “email backend desteği” gibi yeni özellikler mevcut, tüm yeniliklerin listesi burada. 1.2′ye geçmeden önce, önceki sürüme göre deprecated olan değişikliklere göz atmayı unutmayın.
happy hacking!
May 18th, 2010 in
python | tags:
django |
1 comment
grafiklere tıklayınca açılıyorlar.


May 18th, 2010 in
web |
4 comments
Yıllardır XKCD arşivine tam olarak göz atamadım, bugün aşağıdaki diyaloğu -tekrardan- görünce artık vaktinin geldiğini anladım. [buraya random gülüş gelecek]

tüm arşivi indirmeye karar verince, yapmam gereken işlemin basit olduğunu gördüm, ama 700 küsür resmi tek thread/tek process çalışan bir python scriptiyle indirmek uzun sürecekti. bunun üstüne python’da thread pool mevzusunu hem öğrenmek hem de etinden suyundan faydalanmak için araştırdım ve çok kısa bir sürede hallettim. (akabinde python’a yine aşık oldum, tekrardan. literally.)
aşağıdaki betik threading kütüphanesi yardımıyla -biraz daha hızlıca- XKCD arşivini download ediyor. çalışması için sadece ilgili makinede python kurulu olması yeterli.
#!/usr/bin/env python
import Queue
import threading
import urllib
import re, os
"""
XKCD dumper - http://www.xkcd.com
emre yilmaz - www.darkbrown.org
"""
class Fetcher(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
self.__control_download_path()
def run(self):
while True:
comic_id = self.queue.get()
try:
url = "http://www.xkcd.com/%s/" % comic_id
source = urllib.urlopen(url).read()
image = self.retrieve_image_url(source)
self.download_image(image, comic_id)
print "downloading image: %s" % comic_id
except Exception, error:
print "image cannot be retrived for this id: %s" % comic_id
# birinci belli, ikinci kim?
self.queue.task_done()
def retrieve_image_url(self, source):
try:
reply = re.findall("(http://imgs.xkcd.com/.*)</h3>", source)[0]
except:
print error
reply = ""
return reply
def __get_extension(self, image_url):
return re.findall("\.[a-z]{3,4}$", image_url)[0]
def __control_download_path(self):
if not os.path.isdir(XKCD.DOWNLOAD_DIR):
os.mkdir(XKCD.DOWNLOAD_DIR)
def download_image(self, comic_url, comic_id):
extension = self.__get_extension(comic_url)
image_content = urllib.urlopen(comic_url).read()
fp = open("%s/%s%s" % (XKCD.DOWNLOAD_DIR, comic_id, extension), 'wb')
fp.write(image_content)
fp.close()
queue = Queue.Queue()
class XKCD(object):
THREAD_COUNT = 10
COMIC_RANGE = 732
DOWNLOAD_DIR = 'images'
@staticmethod
def fetch():
# thread'leri olustur, ve siraya diz
for i in range(XKCD.THREAD_COUNT):
new_thread = Fetcher(queue)
new_thread.setDaemon(1)
new_thread.start()
# siradaki islere veriyi daya
for item in range(1, XKCD.COMIC_RANGE):
queue.put(item)
queue.join()
XKCD.fetch()
bir süredir işten arta kalan vakitlerde serdar ile birlikte geliştirdiğimiz proje iyice şekillenmeye başladı.

kaynak kodlarını indirmek için buraya, ne olduğuna dair bilgi almak için buraya tıklıyoruz.
April 18th, 2010 in
django | tags:
500t,
ciptis kurtis |
2 comments
jquery için ajax-fancy-captcha diye bir eklenti yazılmış. ilgili eklentiden şu siteden haberdar oldum. eklentinin kendi sitesinde ise 122 adet yorum mevcut. google kayıtları coşmuş, ama ilgili eklentinin güvenliğiyle alakalı bir şey bulamadım. halbuki, ilginç derecede basit ve “aşılabilir” bir mantığı var kodun.
aşağıdaki kod da “aşılabilir” kısmını aşıyor
Read the rest of this entry »
April 15th, 2010 in
php | tags:
ajax fancy captcha |
1 comment
bildiğiniz üzere mysql varsayılan olarak “latin1_swedish_ci” karakter setiyle geliyor. django ise, her yerde – hemen hemen her yerde değil, her yerde- unicode kullanıyor.
modellerinizi yazdıktan sonra “python manage.py syncdb” yapıp, tablolar yaratıldıktan sonra “süper kullanıcı” girmek isterseniz, standart bir mySQL kurulumunda (ubuntu gnu/linux) aşağıdaki hatayı alıyorsunuz:
...
Warning: Incorrect string value: '\xC4\xB1nc\xC4\xB1...' for column 'name' at row 1
django, her şeyi her yerde unicode kullanmasına rağmen, mysql’de tabloları yaratırken karakter seti olarak utf8_*_ci belirtmiyor. hatta belirtmek de istemiyor buradaki hata girdisinde görebileceğiniz üzere. O kısım, mysql sunucunun standart ayarlarıyla çalışıyor. (Django’nun “it is not a bug, it is a feature!” anlayışını sorgulamaya başladım son zamanlarda.)
her neyse, sorunun çözümü basit. mysql sunucusunu standart olarak utf8 ile çalışacak şekilde ayarlamanız gerekiyor. ubuntu için (ve bir çok linux dağıtımı için) root yetkileriyle aşağıdaki yolu takip edebilirsiniz:
/etc/mysql/conf.d/ dizini içine charset.cnf şeklinde bir dosya açın ve içine aşağıdakileri girin ve kaydedin.
[mysqld]
default-character-set=utf8
default-collation=utf8_general_ci
character-set-server=utf8
collation-server=utf8_general_ci
init_connect=’SET collation_connection = utf8_general_ci’
init_connect=’SET NAMES utf8′
skip-character-set-client-handshake
uyarı: uzattığınız dosyanın uzantısı kesinlikle .cnf olmaılıdır. mysql, sadece .cnf uzantılı dosyaları dikkate alıyor.
mysql sunucusunu yeniden başlatın:
/etc/init.d/mysql restart
sorun kalmayacaktır
django-developers ve django-users mail listelerini takip ediyorum. Django ile uygulama geliştirmeye meraklı arkadaşlara da tavsiye ederim. geçenlerde gördüğüm şu thread ise dikkat çekici.
django auth bünyesinde ufak bir decorator barındırıyor. view dosyalarınızın başına koyduğunuz @login_required ile o kısma sadece sisteme giriş yapmış kullanıcıların girebilmesini basitçe sağlıyorsunuz. Django’nun auth modülünün tasarımında kullanıcı pasif durumda olsa bile, authenticated (yetkilendirilmiş) sayılıyor. ilgili dekoratörümüz login_required ise gerekli kontrolü yaparken is_authenticated() değerine bakıyor.
sorun şu ki, pasif bir kullanıcı giriş yapmaya çalıştığında hesap bilgilerini doğru girerse is_authenticated() True dönüyor. is_active kolonu False dönse de. bu da görmemelere gereken sayfaları görebiliyor, yapamamaları gereken işlemleri yapabiliyor olmaları demek.
işin kısası, pasif kullanıcılarınız pek de pasif değiller eğer login_required dekoratörüne güvendiyseniz. aşağıda kendi projem için yazmış olduğum decorator var, projeniz içinde herhangi bir yere gömüp view fonksiyonlarınızdan önce @activeMemberOnly şeklinde kullanabilirsiniz.
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import user_passes_test
def activeMemberOnly(function=None, redirect_field_name=REDIRECT_FIELD_NAME):
actual_decorator = user_passes_test(
lambda u: u.is_authenticated() and u.is_active,
redirect_field_name=redirect_field_name
)
if function:
return actual_decorator(function)
return actual_decorator
yeni projemiz için sphinx full text arama motorunu kullanmayı planlıyorum. Solr ile geçirdiğimiz güzel günler söz konusu olsa da, arama işi için ayrı bir server ayakta tutmak ve bununla HTTP üzerinden iletişime geçmek, türkçe karakter problemleriyle uğraşmak yerine sphinx’i incelemeye aldım. (memnun kalmazsam sırada xapian var.)
ilginçtir ki sphinx’in ubuntu ya da başka bir dağıtım için paketi yok. kendiniz derlemeniz gerekiyor. güncel bir ubuntu’da aşağıdaki adımlarla sphinx’i başarılı bir şekilde kurabilirsiniz.
ilk önce mysql-devel paketlerini kurmak gerekiyor. (bunlar yüzünden biraz zaman kaybettim kurulumda..)
sudo apt-get install libmysqld-dev libmysqlclient-dev
bu aşamadan sonra sphinx’i indirip, arşivi açtıktan sonra sırasıyla aşağıdaki komutları verin:
./configure --with-prefix=/usr/local/sphinx
make
sudo make install
işlemler bittikten sonra konsolda search yazarsanız şöyle bir ekran sizi karşılayacaktır:
root@yunusemre-desktop:/home/yunusemre/Desktop/sphinx-0.9.9# search
Sphinx 0.9.9-release (r2117)
her şey sorunsuz bittiyse gönül rahatlığıyla sphinx dökümantasyonuna atlayabilirsiniz
what the heck is decorators
decorators are the funniest part of python. decorators allow you to execute your additional code at the entry and exit points of a function or a class with a clear syntax. it is very handy when you need to do locking, logging, tracking, caching etc. with your function.
decorators on air
that is the simplest usage of decorators in python.
def sayWelcome(originalFunction):
def decorated():
print("welcome, my bloody sexy function")
originalFunction()
return decorated
@sayWelcome
def myfunction():
print("hi, i am the one who will be decorated")
myfunction()
it’s output will be:
emre@amy:~$ python test.py
welcome, my bloody sexy function
hi, i am the one who will be decorated
emre@amy:~$
you can check out some details in here.
applying it to your django project
if you ever used django auth, you must be aware of bundled decorators in django like @authentication_required, @permission_required.
let’s write a “@limited_access” decorator for django auth. If you don’t wanna deal with user groups/permissions this is for you. This allows you to point views for the users you selected.
from django.http import HttpResponseRedirect
class limited_access(object):
def __init__(self, user_list):
self.user_list = user_list
def __call__(self, view_function):
def wrapped_function(request, *args, **kwargs):
if not request.user.username in self.user_list:
# user is not in access_list, so redirect him/her
return HttpResponseRedirect("http://noaccess.yoursite.com")
else:
return view_function(request, *args, **kwargs)
return wrapped_function
use this in views like this;
@limited_access(["emre", "mary",])
def test_view(request):
return HttpResponse("this view is just for emre and mary.")
any suggestions and comments are wellcome.