27 Mart 2015 Cuma

Django FlatPages Kullanımı

flatpages Django'nun kendisi ile birlikte gelen dinamik sayfalar oluşturulmasını sağlayan bir uygulamadır. Bu yazımızda nasıl kullanıldığından bahsedeceğiz. Bunun için ilk önce uygulamayı projemize dahil etmemiz gerekiyor.
INSTALLED_APPS = (
    ....
    'django.contrib.sites',
    'django.contrib.flatpages',
)
Burada dikkat etmeniz gereken flatpages uygulaması sites uygulamasını kullandığı için sites uygulamasının da projeye dahil edilmiş olması gerekmektedir. Dikkat edilmesi gereken bir diğer nokta ise sites uygulaması için şu satırı settings.py dosyasını eklememiz gerektiğidir.
SITE_ID = 1
Bu işlemden sonra MIDDLEWARE_CLASSES'a şu satırı ekliyoruz.
MIDDLEWARE_CLASSES = (
     ....
    'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
)
Url yapılandırmamızı yapalım.
urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^pages/', include('django.contrib.flatpages.urls')),
)
flatpages uygulamasının url dosyasını içe aktarmış olduk. Bundan sonra yapmamız veritabanı oluşturarak admin panelinden bir sayfa oluşturmak.
python manage.py syncdb
Artık dinamik bir sayfa oluşturmaya hazırız. Admin panelini açtığınız zaman Flat pages alanını göreceksiniz. Tıklayarak yeni birtane oluşturalım. Oluşturduğumuz url'e /pages/lorem-ipsum/ diye gitmeye çalışırsak flatepages/default.html bulunmadı gibi bir hata alırız. Bunun için templates dizini altında flatepages/default.html oluşturuyoruz. Ve içerisine şunları yazıyoruz.
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>
Şimdi tekrardan http://localhost:8000/pages/lorem-ipsum/ adresine gitmeye çalışırsanız sayfanın açıldığını göreceksiniz. Sayfayı oluştururken template name alanını boş bıraktığımız flatepages/default.html şablonunu aramaktadır.
Bir başka kullanım yöntemi ise şu şekildedir. Url tanımlamasını şu şekilde yapabilmekteyiz.
urlpatterns = patterns('',
    ...
    url(r'/lorem-ipsum/$', 'django.contrib.flatpages.views.flatpage', kwargs={'url': '/lorem-ipsum/'}, name='lorem_ipsum'),
)
Daha önceki url tanımlamasını silerseniz. Bu url tanımlamasından sonra http://localhost:8000/lorem-ipsum/ adresi ile tarayıcıdan yine ulaşabilirsiniz. Admin panelinden Flat Plage girerken Advanced Options kısmındaki Template Name alanına eğer herhangi bir isim girerseniz artık bu sayfa girdiğiniz şablona yönlendirilecektir.
Url tanımlasını şu şekilde de yapabiliriz.
urlpatterns += patterns('django.contrib.flatpages.views',
    (r'^pages/(?P<url>.*/)$', 'flatpage'),
)
Aşağıdaki html çıktısı ile, flatpages sayfalarını listeleyebilirsiniz.
{% load flatpages %}
{% get_flatpages as flatpages %}
<ul>
    {% for page in flatpages %}
        <li><a href="{{ page.url }}">{{ page.title }}</a></li>
    {% endfor %}
</ul>
Kaynakça

16 Mart 2015 Pazartesi

Pdb ile Python Debugging

Pdb, Python scriptleri üzerinde debug işlemi yapabilmenize olanak sağlayan bir kütüphanedir. Bu yazıda çok basit bir şekilde kullanımından bahsedeceğiz.
Yazdığımız bir python scriptini debug etmek için komut satırından şu şekilde çalıştırabiliriz.
python -m pdb t.py 
Bu şekilde çalıştırıldığında script debug işlemi kodların en başından başlayacaktır.
Gördüğünüz gibi scripti çalıştırdığımızda bizi doğrudan pdb kabuğuna düşürdü. Burada artık debug işlemimize başlayabiliriz. Tabi bu işlem ile gördüğünüz gibi ilk satırdan itibaren debug işlemine başlamış olduk. Bu şekil de kullanmak yerine herhangi bir satırda bu işlemin başlamısını isteyebiliriz. Bunun için ise script içerisinde herhangi bir satıra şu kodu yazabiliriz.
import pdb; pdb.set_trace()
Bu kodu yazdığımız satıra kadar programımız yorumlanacak ve bu satırdan sonra bizi Pdb kabuğuna düşürecektir. Şimdi yazdığımız basit kodu şu hale getiriyoruz ve ardından komut satırından normal bir şekilde - pdb kullanmadan - çalıştırıyoruz.
def deneme(a):
 print "Bu bir fonksiyon"

print "Pdb'den once"
import pdb; pdb.set_trace()
print "Fonksiyon cagirilmadan once"
deneme(5)
print "Fonskiyon cagirildiktan sonra"
Gördüğünüz gibi program pdb satırına gelene kadar normal bir şekilde yorumlandı ve o satıra geldikten sonra bizi pdb kabuğuna düşürdü. Debug işlemi için yapmamız gereken bu kadar. Şimdi Pdb kabuğuna düştükten sonra neler yapabileceğimize bakalım. Daha önceden dikkatinizi çeti ise l ifadesini kullandım.
  • l(ist) : Yazdığımız kodu listelememizi sağlar.
  • w(here) : Programın olduğu satırı yazar.
  • c(ontinue : Programın kaldığı yerden yorumlanmaya devam etmesini sağlar.
  • b(reak) SatirNumarasi : Satır Numarasına Break Point koyar.
  • tbreak SatirNumarasi : Geçici olarak break point koyar. Birinci işlemden sonra break point silinir.
  • q(uit) : Debug işleminden çıkar.
  • c(lear) : Break pointleri temizlemek için kullanılır. Sorulan soruya y(es) cevabı verilirse break pointler silinir.
  • commands BreakPointNumarasi Girilen Break Point numarasına gidilirken istenilen komutlarında çalışmasını sağlar. Kullanılışı şu şekildedir. Command'ten çıkmak için end ifadesi kullanılır.
  • s(tep) : Bir sonraki satıra geçer.
  • n(ext) : Bir sonraki satıra geçer.
  • İkisi arasındaki fark; Step ile bir fonksiyona girildiği zaman adım adım işlerken n(ext) fonksiyonu işler ve çıkar.
  • j(ump) SatirNumarasi : Yazılan satır numarasına atlar.
  • a(rgs) : Varsayılan fonksiyonun argümanlarını verir.
  • p a : a değişkenin değerini ekrana yazdırır.
  • run : Debug edilen programı yeniden başlatır.

9 Mart 2015 Pazartesi

Django Virtualenv, Gunicorn, Nginx ve Supervisor

Merhabalar bu yazıda bir Virtualenv oluşturmayı, ardından oluşturduğumuz Virtualenv içerisinde bir django projesi oluşturmayı, oluşturmuş olduğumuz bu projemizi nasıl Gunicorn üzerinde koşturacağımızı. Koşturduğumuz bu projemizi Nginx ile nasıl konuşturacağımızı ve en son olarak Gunicorn'u yönetim işlemini nasıl Supervisor'a devredeceğimizden bahsedeceğiz.
Yazımıza geçmeden önce şu komutları sırası ile çalıştırarak sistemimiz güncelleyelim.
sudo apt-get update
sudo apt-get upgrade
Python Virtualenv
Pyton Virtualenv bize özel bir python çalışma alanı yaratır. Ve yüklediğimiz kütüphaneler sadece bu alana yüklenerek sistemin genelini etkilemez. Yaptığımız kurulumların sadece burada geçerli olmasını sağlıyoruz. Bunun ne gibi avantajları var derseniz. En basitinden tek bir sistem altında farklı Django sürümleri ile 1.6 ve 1.7 gibi geliştirilmiş projeleri rahat bir şekilde yayınlayabilirsiniz. İlk önce şu komutu vererek Virtualenv'yi sistemimize kuruyoruz.
sudo apt-get install python-virtualenv
Kurulum ardından kendimize özel bir Virtualenv oluşturalım.
virtualenv django-virt
Oluşturma işleminin ardından dizin içerisini inceleyebilirsiniz. Oluşturduğumuz dizin içerisine girelim ve aktif edelim.
cd django-virt/
source bin/activate
Bu işlemden sonra komut satırının başının değiştiğini göreceksiniz. Artık kuracağımız kütüphaneler bu virtualenv içerisine kurulacaktır.
(django-virt)massumo@ubuntu:~/django/django-virt$
Django Kurulumu
(django-virt)massumo@ubuntu:~/django/django-virt$ pip install django
komutunu çalıştırarak djangoyu oluşturmuş olduğumuz sanal çalışma alanımıza kuruyoruz.
Nginx Kurulumu
Sistemimize Nginx'i kuralım. Bunun için ilk önce aşağıdaki komutu çalıştırarak virtualenv içerisinden çıkalım. Ardından Nginx kurulumu için gerekli olan komutu verelim.
(django-virt)massumo@ubuntu:~/django/django-virt$ deactivate
sudo apt-get install nginx
Gunicorn Kurulumu
Gunicorn çok güçlü bir Python WSGI HTTP Server'dır. Şimdi tekrar virtualenv içerisine girerek Gunicorn'u kuracağız.
$ source bin/activate
(django-virt)massumo@ubuntu:~/django/django-virt$ pip install gunicorn
Django Projesi Oluşturmak
Gunicornu başarılı bir şekilde kurduktan sonra django projesi oluşturabiliriz.
(django-virt)massumo@ubuntu:~/django/django-virt$ django-admin.py startproject django_project
(django-virt)massumo@ubuntu:~/django/django-virt$ cd django_project
(django-virt)massumo@ubuntu:~/django/django-virt/django_project$ python manage.py runserver
Not : Burada komut satırlarının tamamını yazmamın sebebi sizin o an bulunduğumuz dizini ve çalışma alanınızı takip edebilmenizi kolaylaştırmaktır.
Projemiz başarılı bir şekilde ayağa kalktı. Şimdi projeyi Gunicorn ile ayağa kaldıralım.
(django-virt)massumo@ubuntu:~/django/django-virt/django_project$ gunicorn_django --workers=3 --bind localhost:8000
Eğer oluşturduğunuz django projesi 1.7 ve üzeri ise bu komutu çalıştırdığınız da şu şekilde bir hata alacaksınız.
...
    from django.core.management.validation import get_validation_errors
ImportError: No module named validation
Bu hatanın sebebi Django 1.7ile itibaren bazı sınıfların kaldırılması veya yerlerinin değiştirilmesi. Burada da aynı sorun söz konusu. Bu hatanın ortadan kalkması için yapmanız gereken virtualenv içerisine kurmuş olduğumuz gunicorn içerisindeki django_wsgi.py dosyasını düzenlemek. Bu dosyayı şuradan açın
/django-virt/lib/python2.7/site-packages/gunicorn/app/
Bu dizin altındaki django_wsgi.py dosyasını açın ve eski halinden yeni haline getirin.
##Eski hali 
...
##Bu satiri silin
from django.core.management.validation import get_validation_errors
...
def make_wsgi_application():
    # validate models
    s = StringIO()
    if get_validation_errors(s):
        s.seek(0)
        error = s.read()
        msg = "One or more models did not validate:\n%s" % error
        print(msg, file=sys.stderr)
        sys.stderr.flush()
        sys.exit(1)

    translation.activate(settings.LANGUAGE_CODE)
    if django14:
        return get_internal_wsgi_application()
    return WSGIHandler()
...

##Yeni Hali
...
def make_wsgi_application():
    # validate models
    s = StringIO()
    import django
    from django.core.management.base import BaseCommand
    django.setup()
    cmd = BaseCommand()
    import sys
    cmd.stdout, cmd.stderr = sys.stdout, sys.stderr
    cmd.check()
    translation.activate(settings.LANGUAGE_CODE)
    if django14:
        return get_internal_wsgi_application()
    return WSGIHandler()
...
Bu düzeltme işlemini yaptıktan sonra aynı komutu tekrar çalıştırıyoruz.
(django-virt)massumo@ubuntu:~/django/django-virt/django_project$ gunicorn_django --workers=3 --bind localhost:8000
Şimdi hatasız bir şekilde çalıştı. Tarayıcıdan localhost:8000 yazarak çalıştığını görebilirsiniz. Buradaki workers değerini değiştirebilirsiniz. Şimdi gunicorn için bir config dosyası için bir dosya oluşturalım. Ardından ayarlarımızı bu dosya içerisine yazarak bu dosya üzerinden projemizi koşturalım. Virtualenv'nin ana dizinine gunicorn_config.py adında bir dosya oluşturuyoruz ve içerisine şu satırları ekliyoruz.
command = '/home/massumo/django/django-virt/bin/gunicorn'
pythonpath = '/home/massumo/django/django-virt/django_project'
bind = '127.0.0.1:8000'
workers = 3
Bunun ardından bu dosya üzerinden projemizi şu şekilde çalıştırıyoruz.
(django-virt)massumo@ubuntu:~/django/django-virt$ gunicorn -c gunicorn_config.py django_project.wsgi
Projemiz sıkıntısız bir şekilde çalıştı.
Nginx Ayarlamaları
Nginx'i daha önce kurmuştuk. Şimdi ayarlamalarını yaparak projemizi Nginx üzerinde koşturacağız. İlk önce Nginx'i başlatalım.
#service nginx start
Daha sonra /etc/nginx/sites-available dizini içerisine girerek bir conf dosyası oluşturuyoruz.
#####Dosya adı 'myproject'
server {
        server_name localhost;
        access_log off;
 listen 80;
        location /static/ {
                alias /home/massumo/django-virt/django_project/static/;
        }

        location / {
                proxy_pass http://127.0.0.1:8000;
                proxy_set_header X-Forwarded-Host $server_name;
                proxy_set_header X-Real-IP $remote_addr;
                add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
        }
}
Burada dikkatinizi çekmiştir. Nginx bizim Gunicorn ile 8000 portta ayağa kaldırdığımız projeyi dinliyor. Eğer siz az önce komut satırından çalıştırdığımız projeyi CTRL+C vb bir işlem kapattıysanız. Nginx aracılığı ile projeyi koşturamazsınız. O yüzden onu kapatmadan başka bir terminal açarak bu işlemleri yapın. Yani burada nginx bir nevi tünelleme görevi görüyor. Bizim Gunicorn ile ayağa kaldırdığımız projeyi dinleyerek kullanıcıya gösteriyor. Şimdi işlemlerimize devam edelim.
Oluşturduğumuz config dosyasını /etc/nginx/sites-available dizini içerisinde oluşturduk. Oysa nginx ana config dosyası içerisinde aktarma işlemi yaparken /etc/nginx/sites-enabled dizini içerisindeki dosyaları aktarır. Bunu /etc/nginx/nginx.conf dosyasını inceleyerek görebilirsiniz. Bizde bundan dolayı oluşturduğumuz dosyayı ../sites-enabled dizini içerisine linkleyeceğiz. Bunun için siz de şu komutu çalıştırın.
massumo@ubuntu:/etc/nginx/sites-available$ sudo ln myproject ../sites-enabled/myproject
$sudo service nginx restart
Tarayıcıdan localhost yazarsanız projenin çalıştığını görebilirsiniz. Eğer bir hata oluşursa işlemlerinizi kontrol edin.
Supervisor Kurulumu ve Ayarlamaları
Buraya kadar projemizi gunicorn aracılığı ile nginx üzerinde koşturduk. Ama sizde fark etmişsinizdir ki burada bir eksik var. Projemizi terminalde gunicorn üzerinden şu komutla çalıştırmamız gerekiyor ki nginx üzerinden erişilebilsin.
/django-virt$ gunicorn -c gunicorn_config.py django_project.wsgi
Yani bizim bunun kontrolünü sürekli takip etmemiz gerekiyor. Eğer bilgisayarı kapatıp açarsak bu işlemi tekrar yapmamız gerekiyor. İşte bu kontrolleri bizim yerimize Supervisor yapacak. İlk önce kuralım. Virtaulenv içerisinden çıktıktan sonra şu komutu çaıştırın.
sudo apt-get install supervisor
Kurulumu yaptıktan sonra /etc/supervisor/conf.d dizinin açıyoruz ve config dosyası oluşturuyoruz.
##dosya adı 'django_project.conf'

[program:project]
command = /home/massumo/django/django-virt/bin/gunicorn -c /home/massumo/django/django-virt/gunicorn_config.py django_project.wsgi
Config dosyasını Supervisor'a göstermek için şu komutları sırası ile çalıştırın.
sudo supervisorctl reread
sudo supervisorctl update
İşlemlerimiz başarılı bir şekilde gerçekleşti. Artık tarayıcıdan gelerek gunicorn komutunu çalıştırmamıza gerek yok. Supervisor bu işlemi bizim için halledecek. Şuan bilgisayarınızı yeniden başlatsanız bile Nginx üzerinde koşan bir uygulama olması gerekmektedir. Tarayıcıdan http://localhost yazarak ulaşabilirsiniz.

23 Ocak 2015 Cuma

Django Admin Panel Resim Thumbnail

Django'da model içerisinde imagefield kullandığınız zaman admin panelinde form içerisinde bu resmi göremiyoruz. Sadece resmin adı görünmektedir. Bu yazıda bu resmi küçük bir şekilde nasıl görebiliriz ondan bahsedeceğiz. İlk önce model oluşturalım.
#models.py
from django.db import models

class Image(models.Model):
    name = models.CharField(max_length=255)
    image = models.ImageField(upload_to="image")

İlk önce listeleme sayfasında resimleri gösterelim. Bildiğiniz gibi admin sayfasında elemanları listelerken list_display özelliği ile istediğimiz alanları ve istediğimiz herhangi bir fonksiyondan dönen değeri yazdırabiliyoruz. Şimdi model içerisinde bir fonksiyon oluşrulım ve bu fonksiyon bize resmi döndürsün.
class Image(models.Model):
    name = models.CharField(max_length=255)
    image = models.ImageField(upload_to="image")

    def image_thumb(self):
        return '<img src="%s" height="200" width="300"/>' % (self.image.url)
    image_thumb.short_description = 'Resim'
    image_thumb.allow_tags = True
Daha sonra admin.py içerisine şu kodları yazıyoruz.
from django.contrib import admin

class ImageAdmin(admin.ModelAdmin):
    list_display = ['name', 'image_thumb']

admin.site.register(Image, ImageAdmin)
Artık model satıları listelenirken resimleri görebiliyoruz.
Bu işlemden sonra resmin içeriğini görmek için tıklarsanır şöyle bir çıktı alacaksınız.
Gördüğünüz gibi resim görünmemekte sadece resmin yolu görünmektedir. Şimdi burada da resmi gösterelim. Yapmamız gereken admin.py dosyasına şu kodları eklemek.
from django.contrib.admin.widgets import AdminFileWidget
from django.utils.safestring import mark_safe


class ImageWidget(AdminFileWidget):
    def render(self, name, value, attrs=None):
        output = []
        if value and hasattr(value, "url"):
            output.append(('<a target="_blank" href="%s">'
                           '<img src="%s" height="100" title="%s"/></a> '
                           % (value.url, value.url, value.name)))
        output.append(super(AdminFileWidget, self).render(name, value, attrs))
        return mark_safe(u''.join(output))
Burada özel bir widget ekliyoruz. Bu widget aldığı alan için bir geri değer döndürecek. Son olarak yapmamız gereken ise image alanımıza bu widgetı tanımlamak bunun için yine admin.py dosyasında az önce yazdığımız ImageAdmin sınıfını değiştirmek.
class ImageAdmin(admin.ModelAdmin):
    list_display = ['name', 'image_thumb']
    def formfield_for_dbfield(self, db_field, **kwargs):
        if db_field.name == 'image':
            request = kwargs.pop("request", None)
            kwargs['widget'] = ImageWidget
            return db_field.formfield(**kwargs)
        return super(ImageAdmin, self).formfield_for_dbfield(db_field, **kwargs)


admin.site.register(Image, ImageAdmin)
Artık resmi düzenleme sayfasında da görebiliyoruz.
Siz burada kendinize göre biraz daha özelleştirebilirsiniz.

15 Ocak 2015 Perşembe

Django Google reCAPTCHA ve noCAPTCHA Kullanımı

Bu yazıda basit bir şekilde google'ın captcha uygulamalarını sitemize nasıl import edebileceğimizden bahsedeceğiz.
reCAPTCHA
İlk önce https://www.google.com/recaptcha/intro/index.html adresinden kendimiz için bir recaptcha oluşturuyoruz. Buradaki Get reCAPTCHA butonuna tıkladığınızda size Site key ve Secret key oluşturacaktır. Bunları projemizde kullanacağız.
Bu işlemi yaptıktan sonra https://github.com/praekelt/django-recaptcha adresinden uygulamayı indiriyoruz. İndirdikten sonra
cd Downloads/django-recaptcha-develop/
sudo python setup.py install
komutlarını sırası ile çalıştırıyoruz. Kurduktan sonra settings.py dosyasında INSTALLED_APPS değişkenine uygulamayı eklemeliyiz.
INSTALLED_APPS = (
.....
    'captcha',
)
Daha sonra şu satırları settings.py dosyasına ekliyoruz.
RECAPTCHA_PUBLIC_KEY = 'Googledan aldığınız Site Key'
RECAPTCHA_PRIVATE_KEY = 'Googledan aldığınız Secret Key'
RECAPTCHA_USE_SSL = True
Son satır reCAPTCHA'nın SSL kullanması ile ilgili. Eğer isterseniz bu satırı kaldırabilirsiniz. reCAPTCHA'yı kullanmak için artık her şey hazır. Şimdi basitçe kullanalım. İlk basit bir form oluşturuyoruz.
from django import forms
from captcha.fields import ReCaptchaField

class reCAPTCHAForm(forms.Form):
    captcha = ReCaptchaField()
Şimdi bu formu kullanalım. Basit bir view oluşturalım.
from django.shortcuts import render
from go.forms import reCAPTCHAForm
# Create your views here.
def go(request):
 if request.method == "POST":
     form = reCAPTCHAForm(request.POST)
     if form.is_valid():
  """ Form başarılı ise yapılacaklar """
 else:
     form = reCAPTCHAForm() 
 return render(request, 'index.html', locals())
Bu viewa ait olan index.html şablonun içeriği ise şu şekilde;
 
{% csrf_token %} {{ form }}
Artık kullanabilirsiniz. Ekran çıktımız şu şekilde olacaktır.


noCAPTCHA
noCAPTCHA'nın reCAPTCHA'dan neredeyse hiç bir farkı yok. Hemen ufak tefek değişikliklerden bahsedelim. Github sayfasını sizinle paylaşalım. https://github.com/ImaginaryLandscape/django-nocaptcha-recaptcha Bu sayfada kullanımı oldukça basit bir şekilde anlatılmış.
İlk önce kurulum yapıyoruz.
pip install django-nocaptcha-recaptcha
Daha sonra aynı şekilde INSTALLED_APPS'e ekliyoruz.
INSTALLED_APPS = (
....
    'nocaptcha_recaptcha',
)
settings.py dosyasına ayarlamaları ekliyoruz.
NORECAPTCHA_SITE_KEY = 'Googledan aldığınız Site Key'
NORECAPTCHA_SECRET_KEY = 'Googledan aldığınız Secret Key'
Form dosyasını şu şekilde değiştiriyoruz.
from django import forms
from nocaptcha_recaptcha.fields import NoReCaptchaField

class reCAPTCHAForm(forms.Form):
    captcha = NoReCaptchaField()
View dosyamız
from django.shortcuts import render
from go.forms import reCAPTCHAForm
# Create your views here.
def go(request):
 if request.method == "POST":
     form = reCAPTCHAForm(request.POST)
     if form.is_valid():
                """ Doğru ise yapılacaklar """
 else:
     form = reCAPTCHAForm() 
 return render(request, 'index.html', locals())
index.html şablon dosyamız


 
{% csrf_token %} {{ form }}
Burada dikkat etmeniz gereken ekstrandan Google'ın javascript dosyasını çağırıyor olmamız.

9 Ocak 2015 Cuma

Django hvad ile Model'de Çoklu Dil Desteği

Django ile uygulama yaparken bazen model dosyalarınızda çoklu dil desteği oluşturmak isteyebilirsiniz. 3.parti uygulama olarak hvad bunun için müthiş bir kolaylık sağlıyor. Uygulamanın github sayfasına buradan veya kendi dökümantasyonuna buradan ulaşabilirsiniz.
Biz bu yazıda basit bir örnek yaparak model dosyamızı nasıl çoklu dil desteği verebiliriz ve bunu web sitesinde seçim olarak nasıl gösterebiliriz buna bakacağız. İlk olarak basit bir şekilde uygulamayı kuralım.
pip install django-hvad
Ardında uygulamayı projemize dahil edelim.
INSTALLED_APPS = (
    ....
    'hvad',
)
Şimdi uygulamayı kullanabiliriz. İlk önce yapmamız gereken model oluşturmak. Model oluştururken bildiğiniz gibi djangonun kendi model sınıflarından kalıtım alıyoruz. Burada ise yapmamız gereken hvad uygulamasının sınıflarından kalıtım almak. Basit bir model oluşturalım.
from hvad.models import TranslatableModel, TranslatedFields,
class Images(TranslatableModel):
    image = models.ImageField()
    category = models.ForeignKey(Category)

    translations = TranslatedFields(
        title=models.CharField(max_length=200),
        description=models.TextField(),
    )

Burada gördüğünüz gibi bir model oluşturduk. Burada image alanı sabit olduğu için translation içerisine almadık sonuç olarak resim her zaman aynı. Ama title ve description alanları her dil için farklı olarak girilmesi gerektiğinden dolayı TraslatedField alanı içerisin aldık. Şimdi bu model oluşturduğumuza göre admin.py dosyası içerisinde ayarlamalarını yapmalıyız. admin.py dosyası şu şekilde olmalı.
from *.models import Images
from hvad.admin import TranslatableAdmin

class ImagesAdmin(TranslatableAdmin):
    def __init__(self, *args, **kwargs):
        super(ImagesAdmin, self).__init__(*args, **kwargs)
Bunları yaptıktan sonra admin sayfasından ekleme yapmaya çalışırsanız şu şekilde bir pencere ile karşılacaksınız.
Gördüğünüz gibi hemen hemen her dil için ekleme yapabiliyoruz. Burada TranslatedField alanı içerisine almadıklarımızı bir kere girmemiz yeterli aldıklarımızı için her dil için farklı olarak girmeliyiz. Burada bazı dilleri istemeyebilirsiniz. Bunun için istediğiniz dilleri şu şekilde settings.py dosyasına ekleyebilirsiniz.
LANGUAGES = (
    ('tr', 'Turkish'),
    ('en', 'English'),
)
Artık sadece Türkçe ve İngilizce sekmelerini göreceksiniz. Bu şekilde iki dile indirmiş olduk. Peki ekleme yaptıktan sonra bunları view dosyaları içerisinde dillere göre nasıl alacağız. Buda oldukça basit.
images = Images.objects.language('en').all()
Bu şekilde sadece ingilizce yazılan kısımlar gelecektir. Eğer siz bir kayıt eklerken sadece türkçe kısmını girer ve ingilizce kısmını boş bırakırsanız bu sorguda o kayıt gelmeyecektir. Burada language kısmı içerisini session değerinden çekerek kullanıcının seçtiği dile göre veritabanından sorgulama yapabilirsiniz. Bu yazıda çok basit bir şekilde hvad uygulamasının kullanımından bahsettik. Gerçekten de insanın işini çok kolaylaştıran bir uygulama. Daha fazla bilgiye kendi dökümantasyonundan oulaşabilirsiniz.
Kaynakça

10 Aralık 2014 Çarşamba

Numpy: Veri Dosyaları


Python programındaki anlık veriler fiziksel bellek üzerinde depolanır ve program sonlandırıldığında kaybolur. Bu yüzden verileri kalıcı hale getirmek ve daha önceden kaydedilmiş veri blokları programımızda kullanmak için dosyadan veri alışverişi yapma ihtiyacı duyarız. Veri dosya içerisinde yazılı metin olarak durduğundan biçimi, verinin nasıl okunup yazılmasını gerektiğini belirler. Bu bölümde Numpy kütüphanesinin dosya işlemleri için bize sunduğu fonksiyonlarıyla düzenli dosya okuyup yazmanın nasıl yapıldığını göreceğiz.

Hızlı okuyup yazma
Dizileri dosyaya yazdırmanın en basit yolu tofile komutunu kullanmaktır. Bu fonksiyon fiziksel hafızada depolandığı biçimiyle yani ikili(binary) olarak diziyi kaydeder. Bu yöntem hızlı olsa da veri dosyalarının taşınabilir olması istenen durumlar için tavsiye edilmez çünkü kayıt formatı mevcut donanıma ve işletim sistemine bağlıdır. Kaydedilen ikili dosyalar fromfile komutu ile okunabilir. 
>>> from numpy import *                      # Numpy kütühanesini ekliyoruz
>>> dizi = ndarray(shape(2,2), dtype='int')  # 2x2'li dizi oluşturup değer atıyoruz
>>> dizi[0,0] = 1; dizi[0,1] = 2; dizi[1,0] = 3; dizi[1,1] = 4;
>>> print(dizi)
[[1, 2]
[3, 4]]
>>> dizi.tofile('dizi.dat')
>>> dizi_kopya = fromfile('dizi.dat', dtype='int')
>>> print(dizi_kopya)
[1, 2, 3, 4]
dizi.dat dosyasını açmaya çalıştınızda ascii karakterlerden oluştuğunu göreceksiniz. Dosya ikili formatta olduğu için yalnızca yine Python kodu tarafından açılıp okunabilir. Ayrıca görüldüğü gibi dizimizin şekli korumayıp geri alındığında tek boyutlu dizi olarak elde edilmektedir. Bu sebeplerden ötürü kalıcı dosya kayıtları için yukarıda bu tip dosya okuyup yazma tercih edilmemektedir. Yerine daha işlevsel olan savetxt, loadtxt komutları kullanılır.

Metin biçiminde okuyup yazma
Metin veri dosyası istenilen biçimde şekillendirilebilir. Örneğin; birçok ölçüm cihazının yazılım arayüzü ölçüm değerlerini kaydettiği dosyada öncelikle ölçüme ait ortam parametrelerini verir ve ardından sütunlar halinde sonuçları sıralar. Başka bir örnek de HDF gibi yapısal veri dosya biçimleridir. Bu dosyalarda veri ait olduğu nesnenin sınıfın altında verilir. Benzer birçok örnek de verilebilir. İşte bu sebepten ötürü yazılımcılar genellikle farklı biçimleri de sorunsuzca okuyup yazmaya imkan tanıyacak fonksiyonlar ararlar. Python programlama dili, Numpy kütüphanesi sayesinde bize oldukça işlevsel olan loadtxt, savetxt komutlarını bize sunar.  İki komut benzer yapıda olup, adından da anlaşılacağı üzere biri dosyaya kaydetmeyi, diğeri de dosyadan veri okumayı sağlar. Öncelikle bir örnekle dizimizi farklı biçimlerde nasıl dosyaya yazdırabildiğimizi görelim ardından da bu dosyalardaki verileri okumaya çalışalım.
>>> dizi = random.radom(6)          # 6'lık dizi oluşturup rastgele değer atıyoruz
>>> matris = reshape(dizi, (3,2))   # diziyi matris biçiminde şekillendiriyoruz
>>> print(matris)                   # matrisi ekrana yazdırıyoruz
[[ 0.71822401, 0.59663587]
 [ 0.5858213 , 0.12121402]
 [ 0.32291168, 0.32205304]]
>>> # herbir iki sütun da farklı formatta olacak biçimde dosyaya yazdırıyoruz.
>>> savetxt('matris.txt', matris, fmt=['%.2','%.5f'], delimiter=',', newline='\n',\
... header='Dizi yazdiriliyor...', footer='Dizi yazdirildi.', comment='#')
Görüldüğü gibi tek bir komutla veri dosyamızdaki sütünların formatını belirleyip yorum satırları da ekleyerek yazdırabiliyoruz. Buradaki fmt veri sütunlarının formatını, delimiter sütunların hangi karakterle birbirinden ayrılacağını, newline satırların hangi karakterle ayrılacağını, header ve footer sırasıyla alt ve üst yorum cümlelerini, comment yorum cümlelerinin hangi karakterle başlayacağını belirtir. Şimdi dosyamız içindeki verilerin nasıl göründüğünü bakalım.
# Dizi yazdiriliyor...
0.72,0.59664
0.59,0.12121
0.32,0.32205
# Dizi yazdirildi.
Dosyamızı yazdırdıktan sonra benzer şekilde loadtxt komutu ile verileri otomatik olarak dizi nesnesine aktarabiliriz. Sadece değerler diziye aktarılacağı için yorum cümleleri göz ardı edilir.
>>> # matrisi geri al
>>> matris = loadtxt('matris.txt', dtype='float', comments='#', delimiter=',')
>>> print(matris)
[[0.72 0.59664]
 [0.59 0.12121]
 [0.32 0.32205]]
>>> # ilk iki sütunu ayrı ayrı dizilere al
>>> s1, s2 = loadtxt('matris.txt', dtype='float', comments='#', delimiter=','\
... usecols=(0,1), unpack=True) )
>>> print(s1)
[0.72 0.59 0.32]
>>> print(s2)
[0.59664 0.12121 0.32205]
Görüldüğü gibi Numpy kütüphanesinin sunduğu fonksiyonlar sayesinde verilerimizi; standart dosya açma, kapama işlemlerine ve döngü ile değerleri teker transfer etmeye gerek kalmadan kolayca okuyup yazabiliriz.

26 Ekim 2014 Pazar

Numpy: Matrisler ve Basit Lineer Cebir

Sayısal analiz kitaplarının muhtevasını incelediğinizde fark ederseniz; birçoğu ilk bölümlerde doğrusal denklem sistemleri yani lineer cebir konusunu ele alır. Lineer cebirin bu kadar önemli olmasının sebebi, sayısal hesaplamaların çoğunun nihayetinde matris ve vektörlerden oluşan  doğrusal denklemlere indirgeniyor olmasıdır. Derslerimizin şu ana kadar ki kısımlarında genel olarak tek boyutlu vektörlerden bahsettik. Şimdi matrisleri biraz ayrıntılı irdeleyip Numpy kütüphanesini kullanarak temel lineer cebir işlemleri nasıl yapabileceğimiz öğrenelim.  
Matrisler
Matrisleri vektörler gibi oluşturabiliriz. Ancak matrislere özgü fonksiyonlar da mevcuttur. Bunları eye, identity, diag fonskiyonları olarak sıralayabiliriz. eye, identity fonksiyonları birbirine çok benzer olup birim matris oluşturmaya yarar.
>>> from numpy import *    # Numpy kütüphanesini ön alan adı eki olmadan ekliyoruz
>>> print(identity(3))     # birim köşegen matris
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
>>> print(eye(3))          # birim köşegen matris
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
>>> print(eye(3, k=1))     # köşegenin bir üst çapraza birim vektör ekleme 
[[ 0.  1.  0.]
 [ 0.  0.  1.]
 [ 0.  0.  0.]]
>>> print(eye(3, k=-2))    # köşegenin iki alt çapraza birim vektör ekleme 
[[ 0.  0.  0.]
 [ 0.  0.  0.]
 [ 1.  0.  0.]]
diag ise oldukça işlevsel bir fonksiyondur ve girilen bir vektörden köşegen matris oluşturur. Bu komut sayesinde aynı zamanda bant matrisleri de çok kolay oluşturabiliriz.
>>> print(diag([2,3,4], k=0))       # [2,3,4] dizisinden köşegen matris
[[2 0 0]
 [0 3 0]
 [0 0 4]]
>>> print(diag([2,3,4], k=1))       # aynı diziden bir üst köşegen matris
[[0 2 0 0]
 [0 0 3 0]
 [0 0 0 4]
 [0 0 0 0]]
>>>
>>> # üçlü bant matris oluşturma
>>> print(diag(ones(4),k=-1) + diag(2*ones(5),k=0) + diag(ones(4), k=1))
[[ 2.  1.  0.  0.  0.]
 [ 1.  2.  1.  0.  0.]
 [ 0.  1.  2.  1.  0.]
 [ 0.  0.  1.  2.  1.]
 [ 0.  0.  0.  1.  2.]]

Lineer Cebire Giriş
Lineer cebir temel olarak matrislerin özelliklerini ve tek boyutlu vektörlerle olan işlemlerinin halidir. En genel halde bir lineer cebrik sistem A matris x ve b tek boyutlu vektör olmak üzere Ax=b şeklinde bir forma sahiptir. Bu sistemin çözülebilmesi için gerekli olan temel işleçler çarpım ve bölme işlemleridir. Matris-matris, matris-vektör çarpma/bölme işlemi bir önceki yazımızda anlattığımız vektörel aritmetikten farklı olup birebir elemanların çarpımı veya bölümüyle yapılmaz. O yüzden Numpy'de bu amaçla hususi fonksiyonlar tanımlanmıştır. Farkı anlamak için aşağıdaki örneklere göz atalım.
>>> A = ones((4,4))    # 1'lerden oluşan matris
>>> x = ones(4)        # 1'lerden oluşan vektör
>>> b = A*x            # matrisin her bir sütununun x ile vektörel çarpımı
>>> print(b)
[[ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]
 [ 1.  1.  1.  1.]]
>>> b = dot(A,x)      # lineer cebir çarpımı
>>> print(b)
[ 4.  4.  4.  4.]
Görüldüğü gibi ' operatörü bizim istediğimiz manada lineer cebir çarpımını değil vektörel formdaki çarpım işlevini yerini getirir. Bu yüzden Numpy'de matris-vektör çarpımı için dot fonksiyonu tanımlanmıştır. Benzer şekilde lineer cebrik sistemin çözümü için bölme işlemine yani x=b/A ifadesini hesaplayabilmemiz lazım. Bu işlem için yine direkt bölme operatörünü kullanmak yerine linalg alt kütüphanesi içerisindeki inv komutuyla matrisin tersini bulup b vektörüyle çarpabiliriz. 
>>> A = random.random((4,4))     # rastgele kare A matrisi
>>> print(A)
[[ 0.69769186  0.79776825  0.09984681  0.21271922]
 [ 0.05979394  0.72758335  0.0570817   0.59825989]
 [ 0.61698744  0.29374527  0.82004994  0.41084264]
 [ 0.02961924  0.86964469  0.63311203  0.82975882]]
>>> b = random.random(4)         # rastgele b vektörü
>>> print(b)
[ 0.20801453  0.81169016  0.84603751  0.74985329]<
>>>
>>> x = dot(linalg.inv(A), b)    # Ax=b çözümü olarak x=A^-1*b
>>> print(dot(A,x))              # bulduğumuz çözümün sağlamasını yapıyoruz (Ax=b) 
[ 0.20801453  0.81169016  0.84603751  0.74985329]
Lineer sistemin çözümünü yukarıdaki gibi tersini alıp çarpmayla uğraşmak yerine linalg.solve komutunu kullanarak kısa yoldan gerçekleştirebiliriz.
>>> x = linalg.solve(A,b)
>>> print(dot(A,x))       # yine sağlamasını yapıp A*x=b olduğunu kontrol ediyoruz
[ 0.20801453  0.81169016  0.84603751  0.74985329]
Üniversitede lineer cebir almış olanlar bilirler matrisin determinantı ve öz değer/vektörlerini kağı kalemle bulmak oldukça meşakkatlidir. Numpy'nin lineer cebir paketi sayesinde tek bir komutla bu işlemlerimizi basitçe halledebiliriz.
>>> A = diag([2,3,4], k=0)
>>> print(A)             # köşegen A matrisi
[[2 0 0]
 [0 3 0]
 [0 0 4]]
>>> print(linalg.det(A)) # determinantı
24.0
>>> l, v = linalg.eig(A) # eig komutu öz değer ve öz vektörden oluşan iki döndürür
>>> print(l)             # öz değerler
[ 2.  3.  4.]
>>> print(v)             # öz vektörler yazdırılan matrisin sütunlarıdır
[[ 1.  0.  0.]
 [ 0.  1.  0.]
 [ 0.  0.  1.]]
Oldukça geniş bir konu lineer cebrik sistemlere ilişkin yazımızı, Scipy kütüphanesinin konuları arasında daha fazla değinmek üzere şimdilik bitiriyoruz.

21 Ekim 2014 Salı

Django Purge Pagination

Django'da sayfalama için kullanabileceğimiz uygulama olan purge-pagination'dan bahsedeceğiz. Django'nun sayfalama yapısı bizim tam olarak işimizi görmediği için bu sayfalama uygulamasını kullanabiliriz. Genelde sayfa sayısının çok fazla olduğu yerlerde tüm sayfalar gösterilmektense baştan bir kaç sayfa bulunulan sayfa ve sondan bir kaç sayfa gösterilerek güzel bir görüntü oluşması sağlanır. Purge Pagination bu işi halletmemizi sağlıyor. Kurmak için
pip install django-pure-pagination
Uygulamayı kurduktan sonra projemize eklememiz gerekiyor. Bunun için;
INSTALLED_APPS = (
    ...
    'pure_pagination',
)
Uygulamayı yükledikten sonra settings.py içerisinde ayarlamalarını yapabiliriz.
PAGINATION_SETTINGS = {
    'PAGE_RANGE_DISPLAYED': 10,
    'MARGIN_PAGES_DISPLAYED': 2,
}
Buradaki PAGE_RANGE_DISPLAYED ayarı ortada kaç tane sayfa göstericeğini belirtiyor. MARGIN_PAGES_DISPLAYED ise başta ve sonra kaç sayfa olacağını gösteriyor. Yani sayfalama başta 2 sayfa...ortada 10 sayfa...sonda 2 sayfa şeklinde olacak.
Uygulamayı eklediğimize göre kullanabiliriz. Django'nun kendi Pagination yapısı ile kullanımı hemen hemen aynı. Django'da Pagination metodlarınışu şekilde yürklüyoruz.
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
Purge Pagination'da ise sadece uygulama değişiyor. Metodlar ve kullanımları aynı.
from pure_pagination import Paginator, EmptyPage, PageNotAnInteger
View içerisinde şu şekilde kullanabiliriz.
tum_yazilar = Yazilar.objects.filter(onay=1)
yazi_sayfalari = Paginator(tum_yazilar, 10, request=request) 
yazilar = yazi_sayfalari.page(page)
Son olarak ise template içerisinde sayfaları şu şekilde gösterebiliriz.
        {% if yazilar.has_previous or yazilar.has_next %}
            {% load i18n %}
            
    {% if yazilar.has_previous %}
  • {% else %}
  • ‹‹
  • {% endif %} {% for page in yazilar.pages %} {% if page %} {% ifequal page yazilar.number %}
  • {{ page }}
  • {% else %}
  • {{ page }}
  • {% endifequal %} {% else %}
  • ...
  • {% endif %} {% endfor %} {% if yazilar.has_next %}
  • {% else %}
  • ››
  • {% endif %}
{% endif %}
Artık sayfalamamız şuna benzer bir şekilde görünecektir. Sizin temanıza göre stili değişir. Fakat sayfa sayısı bu şekilde olacaktır. Burada resmi uygulamanın github hesabından aldık.
Kaynakça

6 Ekim 2014 Pazartesi

Numpy: Vektörleştirme ve Dilimleme


Bilimsel hesaplamalarda ekseriyetle büyük veri kümeleri üzerinden işlem yapılır. Klasik programlamada, bu türden hesaplamalar liste halindeki sayısal değerlerin döngü içerisinde birer birer çağrılmasıyla yapılır. Ancak günümüzde ise mümkün mertebe döngü kullanımından kaçınılmaktadır. Hatta büyük firmalar tarafından bu amaca yönelik optimize edilmiş program arayüzleri ve kütüphaneler ticari olarak geliştirilmektedir (Matlab, Intel MKL). Bu yazımızda da Python'un Numpy kütüphanesi sayesinde dizi halindeki sayısal veriler üzerinden nasıl hızlı ve basit işlemlerimizi gerçekleştirebileceğimizden bahsedeceğiz. 

Vektörleştirme

Girişte de bahsettiğimiz gibi bir matematiksel işlemi çoğunlukla dizi halindeki verinin tüm elemanları üzerinden gerçekleştirmek isteriz. Bu durumda işlemi for döngüsü içerisinde dizinin herbir elemanı için teker teker yapmak yerine Numpy kütüphanesi sayesinde tek değer üzerinden işlem yapıyormuş gibi gerçekleştirebiliriz. Şimdi aşağıdaki örnekte, polinom ve trigonometri ifadeleri içeren bir hesaplamayı hem döngü ile hem de vektörel formda yapıp karşılaştıralım.
>>> import time as tm   # süre tutma için gerekli olan modül
>>> import numpy as np  # Numpy kütüphanesi 'np' ön adıyla ekliyoruz
>>>
>>> N = 10000               # dizinin eleman uzunluğu
>>> x = np.random.random(N) # argüman dizisi
>>> y = np.zeros_like(x)    # sonuç dizisi
>>> 
>>> t0 = tm.clock()         # kronometre başlangıcı
>>> 
>>> # döngü ile hesap
>>> for i in np.arange(N):
...     y[i] = x[i]**2 + 3*x[i] - x[i]/5 + np.sin(x[i])
>>> t1 = tm.clock()
>>> 
>>> # vektörel hesap
>>> y = x**2 + 3*x - x/5 + np.sin(x)
>>> t2 = tm.clock()
>>> 
>>> print("Döngü ile hesaplama: %5.2f ms" %((t1-t0)*1E3))
>>> print("Vektörel hesaplama: %5.2f ms" %((t2-t1)*1E3))
Döngü ile hesaplama: 106.15 ms
Vektörel hesaplama:  0.67 ms
Görüldüğü gibi vektörel hesaplamayla basit bir hesaplamada bile en az 100 kat daha hızlı işlem yapılabilmektedir. Ayrıca kod metnimiz daha sade ve anlaşılır hale gelmiştir.
Numpy kendi dizi yapıları için temel aritmetik işlemleri (+,-,x,/) ve standart math/cmath kütüphanelerindeki fonksiyonları vektörel formda sağlamaktadır. Eğer harici fonksiyonlar da aynı verimlilikle hesap yapabilmek için vektörleştirmek istenirse bu, vectorize fonksiyonu kullanarak sağlanabilir. 
>>> from math import sqrt           # standart kütüphanedeki kök alma fonksiyonu
>>> def afunc(x):
...    if x<0:
...        return sqrt(-x) + x**2
...    else:
...        return sqrt(x) + x**2
>>> 
>>> afunc_v = np.vectorize(afunc)   # fonksiyonu vektörel hale getiriyoruz
>>> 
>>> N = 10000                       # dizinin eleman uzunluğu
>>> x = np.random.uniform(-1,+1,N)  # argüman dizisi
>>> y = np.zeros_like(x)            # sonuç dizisi
>>> 
>>> t0 = tm.clock()                 # kronometre başlangıcı
>>> 
>>> # döngü ile hesap
>>> for i in np.arange(N):
...    y[i] = afunc(x[i])
>>> t1 = tm.clock()
>>> 
>>> # vektörel hesap
>>> y = afunc_v(x)
>>> t2 = tm.clock()
>>> 
>>> print("Döngü ile hesaplama: %5.2f ms" %((t1-t0)*1E3))
>>> print("Vektörel hesaplama: %5.2f ms" %((t2-t1)*1E3))
Döngü ile hesaplama: 45.30 ms
Vektörel hesaplama:  10.99 ms
Eğer harici fonksiyonumuz sadece temel aritmetik işleçler ve standart kütüphanedeki fonksiyonları içeriyorsa yukarıdaki gibi vektörleştirmeye gerek kalmadan fonksiyonun direk kendisiyle çalışılabilir.

Dilimleme
Önceki konu başlığında tüm dizi elemanları üzerinden nasıl hızlı işlem yapabileceğimizden bahsettik. Ancak bazı durumlarda dizinin tamamıyla değil de belli kısımlarıyla işlem yapmak isteyebiliriz. Mesela; dizinin yarıdan sonrası, çift indisli elemanları gibi... Dilimleme operatörü de işte dizilerdeki elemanlara bu açıdan erişmemizi sağlar. Kullanılışı köşeli parantez içerisindeki iki nokta üst üste işaretleriyle sağlanır [ilk:son:adım]. Parantez içerisindeki tüm değerler tam sayı olmalıdır. Python'daki standart indisleme kuralları geçerlidir. Yani; son indisteki değer aralığa dahil değildir ve adım aralığı geriye doğru ilerlemek için negatif değer alabilir. Aşağıdaki kısa örneklerle kullanışını açıklamaya çalışalım.
>>> N = 10
>>> dizi = np.arange(N, dtype='int')
>>> print(dizi[::])         # dizinin tüm elemanları
[0 1 2 3 4 5 6 7 8 9]
>>> print(dizi[0:N/2:2])    # dizinin yarısına kadar 2'şer aralıklarla
[0 2 4]
>>> print(dizi[::-1])       # tersten geriye doğru birer adımlama
[9 8 7 6 5 4 3 2 1 0]
Dilimleme tekniği özellikle iteratif işlem gerektiren algoritmaların programlanmasında çok önemlidir. Şimdi bize nasıl bir kolaylık sağladığını iyice görmek açısından gerçekçi bir örnek yapalım. Bilindiği gibi analitik türevi mümkün olmayan fonksiyonların ilgili aralıktaki örnek değerleri üzerinden sayısal türevi sonlu farklar yöntemiyle belli doğrulukta hesaplanabilmektedir. Algortimayla alakalı detaylı bilgiyi http://tr.wikipedia.org/wiki/Sonlu_fark referansına bırakıp nasıl kodlandığına bakalım. Karşılaştırmayı mümkün kılmak için analitik türevini bildiğimiz sin fonksiyonunun türevini sayısal olarak üç farklı sonlu fark formülüyle aşağıdaki gibi hesaplıyoruz.
>>> # adım aralığı bilgisini de alacak şekilde eş aralıklı örnekleme
>>> N = 10  # örnekleme sayısı
>>> x, dx = np.linspace(0,+np.pi,N,retstep=True) # [0,+pi]
>>> 
>>> # test fonksiyonu ve analitik türevi
>>> y = np.sin(x)
>>> yp_analitik = np.cos(x)
>>> 
>>> # sonlu farklar
>>> yp_merkezi = ( y[2:N]-y[0:N-2] )/(2*dx) # merkezi fark
>>> yp_ileri = ( y[1:N]-y[0:N-1] )/dx       # ileri fark
>>> yp_geri = ( y[1:N]-y[0:N-1] )/dx        # geri fark
Görüldüğü gibi her bir sonlu fark hesabını dilimleme operatörü sayesinde birer satırda gerçekleştirebildik. Not olarak belirtmek gerekir ki, ileri ve geri fark ifadeleri birbirine eşit görünmekle birlikte açı dizisinde (x) karşılık geldiği noktalar farklıdır.
Yazımızı, bulduğumuz sonuçları görselleştirip, çıktılarını inceleyerek bitirelim. Aşağıdaki kodda Matplotlib kütüphanesi kullanılarak analitik türevle birlikte sayısal türevler tek bir grafik üzerinde gösterilmek istenmiştir. İleri ve geri fark sonuçları ise birbirleriyle benzer hata oranıyla analitik değere iyi bir biçimde yakınsamaktadır. Ancak beklediğimiz gibi, merkezi fark yöntemiyle hesaplanan türev diğer ikisinden daha az yanılmayla sonuca yaklaşmıştır. Örnekleme sayısını arttıracak olsaydık sayısal türev değerleri giderek daha fazla analitik değere benzeyecek, grafik eğrileri üzerinde ayırt edilemez hale gelecekti.
>>> import matplotlib.pyplot as plt # matplotlib kütüphanesini çizdiricisi
>>> 
>>> fig = plt.figure()              # yeni grafik ekranı
>>> 
>>> plt.plot(x,yp_analitik, color='blue', label='analitik')
>>> plt.plot(x[1:N-1],yp_merkezi, color='red', label='merkezi')
>>> plt.plot(x[0:N-1],yp_ileri, color='yellow', label='ileri')
>>> plt.plot(x[1:N],yp_geri, color='green', label='geri')
>>> plt.legend(loc='upper right')
>>> plt.title('Sinüs Fonksiyonunun Türevi')
>>> plt.xlabel('x')
>>> plt.ylabel('y\'(x)')
>>> plt.grid()
>>> plt.xlim(0,+np.pi)
>>> plt.ylim(-1,1)
>>> plt.show()

Kaynaklar:
[1] Langtangen H. P., Python Scripting for Computational Science, Springer, 2007

29 Eylül 2014 Pazartesi

PyQt Class Kullanımı

       Grafiksel kullanıcı arayüzüne sahip programlar genellikle bir çok pencere ve işlev içermektedir. Dolayısıyla bütün bu pencere ve işlevleri tek bir dosyada tutmak oldukça kafa karıştırıcı bir hale gelmeye başlar. Bu tür bir karmaşıklığı önlemek ve programımızı daha modüler bir hale getirmek için classları kullanırız.

Şimdi bir önceki konuda yazdığımız programı class kullanarak tekrar yazalım:
# !/usr/bin/env python
# -*- coding: cp1254 -*-
 
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class sinifProgrami(QDialog):
    def __init__(self, parent=None):
        super(sinifProgrami, self).__init__(parent)

        self.metin = QLabel('
PythonDersleri.com
') self.butonKirmizi = QPushButton('Kırmızı') self.connect(self.butonKirmizi, SIGNAL('pressed()'), self.kirmiziMetin) self.butonMavi = QPushButton('Mavi') self.connect(self.butonMavi, SIGNAL('pressed()'), self.maviMetin) izgara = QGridLayout() izgara.addWidget(self.metin, 0, 1, 2, 1) izgara.addWidget(self.butonKirmizi, 0, 0) izgara.addWidget(self.butonMavi, 1, 0) self.setLayout(izgara) self.setWindowTitle('PyQt Grid Layout') self.setFixedSize(450, 150) def kirmiziMetin(self): self.metin.setText('
Merhaba Dünyalı :)
') def maviMetin(self): self.metin.setText('
Uygar Köroğlu
') uygulama = QApplication([]) pencere = sinifProgrami() pencere.show() uygulama.exec_()

Bu kodu çalıştırdığımızda da çıktı değişmeyecektir:

PyQt classları QWidget nesnesi olabileceği gibi QDialog nesnesi de olabilir. Hangisinin nesnesi ise ona ait tüm özellikleri de taşıyacaktır. 
Yazmış olduğumuz kodları satır satır açıklamaktan ziyade bu koda baktığımızda farklı olarak gözümüze ilk şu satır çarpmaktadır:
super(sinifProgrami, self).__init__(parent)
Bu satırda parenttan bahsettik yani ebeveyn. Program alt pencerelerden oluşmaya başladığında, hangi pencerenin hangi pencereye ait alt pencere olduğunu ayırt etmek için bu yapı kullanılır. Biz bu pencerenin bir alt pencere olmadığını, bizim penceremizin bir ana pencere olduğunu parent=None ifadesiyle belirttik.
Bir class'ın başlamasını sağlamak için super() metodu kullanılmakta. super() metodu parametre olarak; ilk parametrede class'ın adını, ikinci parametrede ise self olarak kendisini alır. __init__() metoduna ise hangi pencerenin alt penceresi olduğunu parametre olarak yazarız.

28 Eylül 2014 Pazar

Veri Tabanından Model Dosyası Oluşturma

Bildiğiniz gibi Django'da veritabanı oluşturmak için ilk önce models.py dosyasında veritabanımınızın nasıl olacağına dair tanımlamaları yapıyoruz ve ardından
python manage.py syncdb
komutu ile tablolarımızı oluşturubiliyoruz. Peki ya tasarımını yaptığımız bir veritabanını model dosyası içerisine aktarmak istersek ne yapacağız. Bunun çözümüde yukarıdaki komut kadar basit. Vermemiz gereken komut şu şekikde.
python manage.py inspectdb > app/models.py
Bu şekilde app uygulaması içerisindeki models.py dosyası içerisine veritabanına uygun olan model tanımlamaları yapılacaktır. Şu tarz tanımlamalar görebilirsiniz.
class Message(models.Model):
    id = models.IntegerField(primary_key=True)
    message = models.CharField(max_length=30)
    class Meta:
        managed = False
        db_table = 'app_message'
Peki Django'nun kendi çekirdek tablolarını oluşturmak için ne yapacağız. Bunun için yine modelden tablo oluşturmamızı sağlayan komutu verebilirsiniz.
python manage.py syncdb
Kaynakça

27 Eylül 2014 Cumartesi

PyQt Pencere Düzenleri

       Grafiksel arayüze sahip programlar genellikle birden çok pencereye sahiptirler. Ve bu pencereler de genellikle kendi içlerinde farklı parçacıklar bulundurmaktadırlar. Yani kendilerine ait butonları, labelları, text alanları gibi parçacıkları olmaktadır. Biz de programlarımızı yazarken kullandığımız parçacıkların sayısı arttığında, bunları penceremize nasıl yerleştireceğimiz konusunda birtakım pencere düzeni uygulama gereksinimi duymaktayız.

Örneğin; yerleştirmek istediğimiz bir label ve bir butonumuz olsun. Bunları yandaki şekildeki gibi yan yana veya alt alta koymak isteyebiliriz.

Bu yapılar Layout olarak isimlendirilirler. Biz burada kutu demeyi tercih ediyoruz. Bu şekillerden ilki dikey bir kutu (QVBoxLayout) diğeri ise yatay bir kutudur (QHBoxLayout). Bu kutulara eleman eklemek istediğimizde (addWidget) dikey kutuda her eklenen eleman alta gelecek şekilde, yatay kutuda ise sağ tarafa gelecek şekilde ekleme işlemi gerçekleşmektedir. Bir parçacık eklemek için addWidget() metodu kullandığımız için penceremizin de QWidget() nesnesi olması gerekir.

Şimdi bu bahsettiklerimiz hakkında bir örnek yazalım ve bu örnek üzerinden kodları açıklayalım.

# !/usr/bin/env python
# -*- coding: cp1254 -*-
from PyQt4.QtGui import *

uygulamam = QApplication([])
pencere = QWidget()
etiket = QLabel('PythonDersleri.com')
buton = QPushButton('Butonum')

yatayKutu = QHBoxLayout()
yatayKutu.addWidget(etiket)
yatayKutu.addWidget(buton)

pencere.setLayout(yatayKutu)
pencere.setWindowTitle('Programım')
pencere.show()

uygulamam.exec_()

1. Satır = Yazdığımız kodların Python kodu olduğunu ve Python'un dizinini belirtiyoruz. (Linux için)
2. Satır = Türkçe karakterlerin desteklenmesini istediğimizi belirtiyoruz.
3. Satır = Grafiksel arayüz için gerekli modülü programımıza dahil ettik.
5. Satır = Bir QApplication nesnesi oluşturuyoruz.
6. Satır = Bir tane Widget oluşturduk.
7. Satır = İçeriği "PythonDersleri.com" olan bir Label oluşturduk.
8. Satır = Üzerinde "Butonum" yazan bir buton oluşturduk.
10. Satır = Yatay şekilde eleman ekleyebileceğimiz bir kutu oluşturduk.
11. Satır = Oluşturduğumuz yatay kutunun içine Labelımızı ekledik.
12. Satır = Yine yatay kutunun içine butonumuzu da ekledik.
14. Satır = Pencere düzenimizin oluşturduğumuz yatay kutu olacağını belirttik.
15. Satır = Program penceremizin başlığında "Programım" yazmasını belirttik.
16. Satır = Penceremizin görüntülenmesini istedik.
18. Satır = Uygulamamızın çalışmasını istedik.

       Kodu çalıştırdığımızda ise bize şöyle bir çıktı verecektir:

       Çalışma Sorusu: Yukarıda yatay bir kutu için yazmış olduğumuz kodu dikey bir kutu için yeniden yazın; ancak bu kez üstte buton altta label bulunsun.

PENCERE BOYUTLARI VE YERİ

       Yukarıda yazmış olduğumuz gibi bir kod yazdığımızda programımız parçacıkları yerleştirebildiği minimum boyutlarda açılacaktır. Biz istersek bu boyutları değiştirebiliriz (resize). Ancak bu değiştirme işlemi küçültme yönünde değil, büyütme yönünde yapılabilmektedir. Küçültmeye çalıştığınızda ise parçacıkların yerleştirildiği minimum boyutlarda açılacaktır. Boyutları değiştirebileceğimiz gibi programın sol üst köşeden itibaren kaç piksel uzaklıkta başlayacağını da belirleyebiliriz (move). Bu değişikliklerin nasıl olduğunu görmek için ise yukarıda yazmış olduğumuz koda pencere.setWindowTitle('Programım') satırından sonra aşağıdaki kodları ekleyin ve değişikliği görmek için çalıştırın.
pencere.resize(300, 100) # Yeni boyutlar
pencere.move(50, 50) # Sol üst köşeden uzaklık

25 Eylül 2014 Perşembe

Numpy: Dizi Oluşturma

Bu bölümde sayısal verilerin depolandığı dizileri oluşturma yöntemlerini öğreneceğiz. Python programlama dili Fortran ve C türevi dillerden farklı olarak veri bloğu için fiziksel bellekteki hafıza ayarlama işini otomatik olarak yapar. Dolayısıyla biz sadece dizimizin niteliğini ve niceliğini belirtip oluşturabiliriz. Diziyle işimiz bittiğinde Python yine bizim ek bir komut çalıştırmamıza gerek kalmadan hafızada ayrılmış yeri boşaltır. Böylece diğer programlar için de yer açılmış olur.
 
Dizi Nesnesi
Python nesne tabanlı bir programlama dilidir. Bu yüzden herbir modül veya kütüphane bir sınıf olarak düşünülebilir. Bu sınıfların nesneleri temelde constructor adı verilen inşa fonskiyonları ile oluşturulur. İnşa fonksiyonlarının parametrelerini inceleyerek nesnelerimizin temelde hangi özelliklerini barındırdığını öğrenebiliriz. Aşağıdaki örneğe göz atalım.
>>> from numpy import * # Numpy kütüphanesini ad alanı ön eki olmadan ekliyoruz
>>> ndarray(shape=(2,3), dtype=float32)
array([[  3.77839489e+22,   9.18355102e-39,   1.38829441e-40],
       [ -3.76174156e-37,   7.62234898e-39,   7.00649232e-45]], dtype=float32)
İnşa fonksiyonunun bazı parametreler aldığını görüyoruz. Bunlardan shape, oluşturmak istediğimiz boyutu bildiren bağlı sıralılardır (tuples). Yukarıdaki örnekte de bu parametreyle birlikte 2x3'lük yani iki satırdan 3 sütundan oluşan bir dizi oluşturmak istediğimiz belirtmiş olduk. dtype özelliği ise bu dizide hangi tip verilerin saklanacağını belirtir. Biz burada standart 'float32' tip veri (varsayılan) türünden bir diziyi tercih ettik. Farklı tip Python veril tipleri ('int', 'float64' vb.) de dizilerde depolanabilir.
ndarray sınıfı hafızanın elverdiği ölçüde keyfi boyutlu dizileri destekler. Örneğin; aşağıda tamsayılardan oluşan 2x2x2x2'lik bir dizi oluşturulmuştur. 
>>> ndarray((2,2,2), 'int32')
array([[[ 50398851, 505910976],
        [505910976, 505910976]],
       [[ 68431072, 657601396]]]),
        [   657961,  48016344]]])
Yazımızın bundan sonraki bölümlerinde ise anlatımı kolaylaştırmak amacıyla genelde tek boyutlu dizilerle çalışılacaktır.

Elemanlara Erişim
Dizinin herhangi bir elemanına erişmek için köşeli parantez '[ ]' operatörünü kullanabiliriz. Python'da ilk indis '0'dan başlar, ve diğer programlama dillerinden farklı olarak negatif indisleri destekler. Negatif indislerde ise ilerleme yönü sondan başa doğrudur.
>>> dizi = ndarray(5) 
>>> print(dizi)
[  3.83049187e+238   3.45262638e-316   0.00000000e+000   3.83711926e+238
   6.35862486e-321]
>>> dizi[1] = 5.0  # baştan ikinci elemana değer atandı
>>> dizi[-1] = 5.0 # en sondaki elemana değer atandı
>>> print(dizi)
[  3.83049187e+238   5.00000000e+000   0.00000000e+000   3.83711926e+238
   5.00000000e+000]
Dizinin boyutu shape fonksiyonuyla elde edilir. Tek boyutlu diziler için standart kütüphanedeki len fonksiyonu da kullanılabilir. 
>>> shape(dizi)
(5,)
>>> len(dizi)
5
Diziye ait elde edilmek istenen en önemli bilgilerden biri de maximum ve minimum değerleri, ve bunların indis konumlarıdır. max/min fonksiyonları bu değerleri, argmax/argmin fonksiyonları da bu değerlerin bulunduğu indisleri bize bildirir.
>>> min(dizi)
0.0
>>> argmin(dizi)
2
>>> max(dizi)
3.837119259946211e+238
>>> argmax(dizi)
3

Ön Tanımlı Dizi Oluşturma
Numpy dizilerini oluşturmanın aslında birçok yolu vardır. İlk olarak standart liste tipindeki verilerin nasıl diziye dönüştüğünü görelim.
>>> liste = ([1,2,3])
>>> dizi = array(liste, 'float32')  # tam sayı yerine ondalıklı olarak depolar
>>> print(dizi)
[ 1.  2.  3.]
Dizileri de tolist fonksiyonuyla tekrardan listeye dönüştürebiliriz.
>>> liste = ([4,6,7])
>>> dizi = array(liste, 'int32')
>>> liste2 = dizi.tolist()
>>> print(liste2)
[4, 6, 6]
Dizi elemanlarını baştan '0' veya '1' atayarak, veya inşa fonksiyonunda olduğu gibi varsayılan değer atayarak oluşturabiliriz.
>>> dizi = zeros(4)
>>> print(dizi)
[ 0.  0.  0.  0.]
>>> dizi = ones(4)
>>> print(dizi)
[ 1.  1.  1.  1.]
>>> dizi = empty(4)
>>> print(dizi)
[  7.35794000e-295   7.01521574e-295   7.01647004e-295   7.01440942e-295]
Dizileri önceden belirli aralıklarla da oluşturabiliriz. arange fonksiyonu sırasıyla başlangıç, bitiş ve adım aralığını parametre olarak alıp bitiş noktasının dahil olmadığı bir dizi oluşturur. linspace başlangıç ve bitiş değerleri arasındaki istenilen sayıda eş aralıklı değer türetir. arange'ten farklı olarak linspace'te adım aralığı değil örnek sayısı parametre olarak girilir ve bitiş noktası da türetilen değerler içindedir. 
>>> arange(1,10,1)
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> linspace(1,10,3)
array([1., 5.5, 10.])
logspace ise eş aralıklı örnek değerleri, istenilen tabanda logaritmik olarak verir.
>>> logspace(1, 10, N=2) # varsayılan taban değeri '10' kullanıldı
array([  1.00000000e+01,   1.00000000e+10])
>>> logspace(1, 10, N=3, base=2)
array([2., 45.25, 1024.]) # log2(2)=1, log2(45.25)=5.5, log2(1024)=10

Rastgele Dizi Oluşturma
Numpy kütüphanesindeki random sınıfı ve alt fonksiyonlarını kullanarak rastgele değerlerle doldurulmuş diziler elde edebiliriz.
>>> random.random(3)
array([ 0.5878516 ,  0.01153192,  0.84747563])
Değerler görüldüğü gibi [0,1) aralığında türetilmiştir. Eğer keyfi aralıkta olması istenirse bu uniform alt fonksiyonu kullanarak sağlanabilir
>>> # [a=3,b=5) yarı açık aralıkta rastgele N=4 adet değer
>>> random.uniform(3,5,4)
array([ 4.37716131,  3.04042835,  3.08056492,  4.89028642])

Kaynaklar:
[1] Langtangen H. P., A Primer on Scientific Programming with Python, Springer, 2009

24 Eylül 2014 Çarşamba

Numpy & Scipy

pythondersleri.com yeni bir yazı dizisi "Numpy ve Scipy : Bilimsel Hesaplamalar İçin Python" ile karşınızda! Bu yazı sayesinde akademik çalışmalar ve endüstriyel uygulamalardaki hesaplamalar için Python programlama diline bir miktar vakıf olabilmeyi amaçlıyoruz. Meselenin kapsamı geniş olduğu için ilk yazımızda içerik hakkında özet bilgi vermeyi uygun gördük.
Python'un günümüzdeki popülerliğinin en önemli sebeplerinden biri de hesaplamalı bilimlerdeki işlevselliğidir. Üst seviye bir programlama dili olan Python bu işlevselliği sayesinde; alt seviye programa dillerinde (C, C++, Fortran) yapılabilen karmaşık büyük çaptaki hesaplamaları kıyaslanabilir bir performansta, kullanıcıya büyük kolaylıklar sağlayarak (Matlab vb.) gerçekleştirebilmektedir. Python aslında bu fonksiyonelliğini biraz da modül, paket veya kütüphane olarak adlandırılan eklentilere borçludur. Bu paketlerden en meşhurları yazı dizimizin kapsamını da oluşturan Numpy ve Scipy kütüphaneleridir. Numpy genel olarak dizi/vektör/matris hesaplamaları için özelleşmiş bir kütüphane olup, büyük çaptaki veri kümeleri üzerinden işlem yapmayı kolaylaştırır. Scipy ise bünyesinde, sık kullanılan matematiksel rutinleri ve fiziksel problemlerinin bilgisayar ortamında ifade edilmesine yönelik fonksiyonları barındırmaktadır. Dersler kapsamında yeri geldiğinde ayrıca, işlenilen ve sonuç olarak elde edilen verilerin görselleştirilmesi amacıyla Matplotlib kütüphanesinde bahsedilip pratik bilgiler verilmeye çalışılacaktır.

?

Yazılardaki örnekler, Python 3.3 sürümünde çalışan kodlar olup Numpy 1.8 ve Scipy 0.13 kütüphaneleri uyumludur. Ancak ilgili kütüphanelerin kurulu olduğu herhangi bir Python 3x sürümü kullanılmasının bir sıkıntı oluşturmayacağı kanaatindeyiz. Paketlerin yüklenmesi ile ilgili yönergeler için http://www.scipy.org sitesine göz atabilirsiniz. Windows kullanıcılarına kolaylık sağlamak amacıyla üçüncü şahıslar tarafından ikili(binary) dosyalar hazırlanıp ücretsiz olarak dağıtılabilmektedir. Bunların içerisinde, diğer pek çok eklentiyi de bulabileceğiniz http://www.lfd.uci.edu/~gohlke/pythonlibs adresini tavsiye edebiliriz.
Scipy kütüphanesi arka planda Numpy dizilerinden istifade etmektedir. Bu yüzden derslerimizde öncelikle Numpy anlatılacak ardından Scipy'e geçilecektir. Numpy kapsamında aşağıdaki konulara değinilecektir.
  • Dizi oluşturma
  • Vektörleştirme ve dilimleme
  • Matrisler ve basit lineer cebir
  • Veri dosyaları
Scipy kapsamında ise aşağıdaki konu başlıkları takip edilmeye çalışılacaktır.
  • Lineer cebir
  • İnterpolasyon ve eğri uydurma
  • Sayısal integral ve türev alma
  • Fourier dönüşümü
  • Özel fonksiyonlar
  • Fizksel büyüklükler ve sabitler
  • Sembolik matematik
  • Dosya okuyup yazma

22 Eylül 2014 Pazartesi

Daha önce Django Projesini Apache ve Mod_WSGI ile Yayınlamak yazısında Apache sunucusu üzerinde nasıl proje yayınlanacağından bahsetmiştik. Bu yazıda ise çok basit bir şekilde bir apache sunucu üzerinde birden fazla Django projesi nasıl çalıştırılır bundan bahsedeceğiz. Çözümü oldukça basit. Yapmamız gereken Apache VirtualHost tanımlaması yaparken projeleri process'lere bölmek. Bu şekilde diğer projenin süreçleri projemizi hataya sürüklemeyecek ve birden fazla proje tek bir sunucuda sorunsuz bir şekilde çalışabilecektir.
Birinci proje için VirtualHost tanımlaması :

ServerAdmin info@proje1.com
ServerName proje1.com
DocumentRoot /var/www/proje1


Alias /static/ /var/www/proje1/static/
WSGIDaemonProcess proje1
WSGIScriptAlias / "/var/www/proje1/proje1/wsgi.py" process-group=proje1
ErrorLog /var/log/apache/proje1/error_log
TransferLog /var/log/apache/proje1/access_log
...

İkinci proje için VirtualHost tanımlaması :

ServerAdmin info@proje2.com
ServerName proje2.com
DocumentRoot /var/www/proje2


Alias /static/ /var/www/proje2/static/
WSGIDaemonProcess proje2
WSGIScriptAlias / "/var/www/proje1/proje1/wsgi.py" process-group=proje1
ErrorLog /var/log/apache/proje1/error_log
TransferLog /var/log/apache/proje1/access_log
...

Burada öenmli olan 8 ve 9. satırlar. 8. satırda proje için bir Process tanımlaması yapıyoruz. 9. satırda ise bu processi projemize atama işlemini yapıyoruz. Eğer bu tanımlamaları yaparsanız bir sunucu üzerinden istediğiniz kadar projeyi çalıştırabilirsiniz.

18 Eylül 2014 Perşembe

Pushover Kullanımı

Pushover, Telefona bildirim almanızı sağlayan bir servistir. Bunun için kullanımı oldukça basit olan bir api sağlamaktadır. Bu yazıda pushover apisinin Python ile nasıl kullanıldığından bahsedeceğiz?
Yapmamız gereken ilk önce https://pushover.net/ adresini ziyaret ederek üye olmak. Üye olduktan sonra ana sayfada size bir key verildiğini göreceksiniz.
Bize verilen keyi birazdan kullanacağız. Ama ondan önce resmin altında gördüğünüz Register an Application linkinden bir uygulama oluşturmamız gerekiyor. Zorunlu olan alanları doldurduktan sonra Create Application diyerek uygulamayı oluşturuyoruz.
Ve bize bu uygulamayı kullanabilmek için bir token veriliyor.
İşte bize gerekli olan kullanıcı key'ini ve uygulama token'ini elde ettik. Bundan sonra Device Clients sayfasından uygulamayı telefonumuza indirip kullanıcı girişi yapıyoruz. Şimdi apiyi kullanabiliriz. Pushover için Python ile yazılı kütüphane mevcut. İlk önce onu kurmalıyız.
sudo pip install python-pushover
Pushover kullanabilmek için bu kütüphaneyi kullanmak zorunda değilsiniz. requests kütüphanesini kullanarak isteği kendiniz de yapabilirsiniz. Ama kullanımı daha basit olduğu için bu kütüphaneyi kullanacağız. Basit bir şekilde kullanımı şöyle:
from pushover import Client

client = Client("User Key", api_token="Api Token")
client.send_message("Test içeriği", title="Test Başlığı")
Eğer her şey yolunda ise bu programı çalıştırdığınızda telefonunuza bildirim gelmiş demektir. Eğer gelmedi ise adımları tekrar gözden geçiriniz. Daha ayrıntılı bilgiye https://pushover.net/api adresinden ulaşabilirsiniz.

Kaynakça

3 Eylül 2014 Çarşamba

Django 1.7 ve Migrations

Ve Django'nun 1.7 sürümü yayınlandı. Bu bizim için çok anlam ifade ediyor. Çünkü artık biz de Migration özelliğine sahibiz. Veritabanımızda oluşturmuş olduğumuz tablolara sütünlar ekleyebilir veya silebiliriz. Bildiğiniz gibi Django'nun 1.7'den önceki sürümünde bir tablo sadece bir kere oluşturuluyordu. Yani projeyi yaptıktan bir süre sonra tablo üzerinde değişiklik yapmanız demek tablo içerisindeki verileri kaybetmeniz demektir. Güncellenmiş halini yeniden oluşturmak için tabloyu silerek tekrardan oluşturmanız gerekiyordu. İşte bu sorun 1.7 ile birlikte gelen Migration ile ortadan kalktı.

20 Ağustos 2014 Çarşamba

PyQt Akıllı Diyaloglar

     Akıllı diyalogların akılsız diyaloglardan oluşturulma yönünde bir farkı yoktur. Sadece akılsız diyaloglara oranlara birtakım avantajları vardır. Bu avantajlar ise kullanılacak duruma göre dezavantaj da olabilir. Akıllı ve akılsız diyalogların farklılıklarına kısaca değinelim.

Akılsız diyaloglarda bir pencere açıldığında onay butonları veya çarpı işaretinden kapatılması sonucu sadece kullanıcıya görünmez olur; ama bellekte yer kaplar. Ve her yeni çağrılışında yeni bir pencere oluşturmaktadır. Bunu diyalog sonuna ekleyebileceğimiz del diyalog komutu ile çözebiliriz.
Ayrıca akılsız diyaloglar kendisini çağıran pencere ile etkileşim içinde değildir. Yani yapılan değişiklikler onaylanmadan görüntülenemez. Onaylandığında da kalıcı olarak değişiklik yapılmış olur. Bu durumda önceki duruma dönülemez.

İşte bu bahsettiğimiz durumları akıllı diyaloglar giderir. Akılsız diyaloglarda yapılan değişiklikler, kendisini çağıran pencerede gerçekleşmekte; fakat akıllı diyaloglarda yapılan değişiklikler diyaloğun kendisinde yapılır.
Diyalog kapatıldıktan sonra kendisini sildiğinden bellekte yer kaplama durumu da söz konusu değildir. Bunu da örneğimizde self.setAttribute(Qt.WA_DeleteOnClose) kodu ile sağlayacağız. Bu kodu akılsız diyaloglara koyamıyoruz; çünkü akılsız diyaloglar kendisini çağıran pencereye değişikliklere dair veri aktarmaktadır. Oysaki bu değişiklikler akıllı diyaloglarda kendi içinde halledilmiştir.

Şimdi bir metnin yazı tipini akıllı diyalog ile değiştirebileceğimiz bir örnek yapalım. Kodlarımız şu şekilde:
from PyQt4.QtCore import *
from PyQt4.QtGui import *

simgeler = 'D:/Simgeler/orange-moonlight-icons/png/64x64/'
# simgeler => http://dryicons.com/free-icons/preview/orange-moonlight-icons/

class yaziTipiDiyalogu(QDialog):
    def __init__(self, parent=None):
        super(yaziTipiDiyalogu, self).__init__(parent)
        self.parent = parent

        self.setAttribute(Qt.WA_DeleteOnClose)
        # Üst satırda yazmış olduğumuz kod pencere kapatılırken doğrudan silinmesini sağlar.
        # Böylelikle bellekte yer kaplamamış olur.

        self.yaziTipiListesi = QFontComboBox()
        self.yaziTipiListesi.setCurrentFont(QFont(self.parent.yaziTipi))

        butonKutusu = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        #Butonların üstündeki yazıları Tamam ve İptal olarak değiştirelim.
        butonKutusu.button(QDialogButtonBox.Ok).setText('Tamam')
        butonKutusu.button(QDialogButtonBox.Cancel).setText('İptal')
        self.connect(butonKutusu, SIGNAL('accepted()'), self.kabul)
        self.connect(butonKutusu, SIGNAL('rejected()'), self.reject)

        pencere = QGridLayout() # Izgara pencere düzeni
        pencere.addWidget(QLabel('Yazı Tipi Seçimi: '), 0, 0)
        pencere.addWidget(self.yaziTipiListesi, 0, 1)
        pencere.addWidget(butonKutusu, 1, 0, 1, 2)
        self.setLayout(pencere)

        self.setWindowTitle("Yazı Tipini Ayarla")
        self.setWindowIcon(QIcon(simgeler + 'edit.png'))

    def kabul(self):
        self.parent.yaziTipi = self.yaziTipiListesi.currentFont().family()
        self.parent.label.setText(self.parent.metin % self.parent.yaziTipi)
        QDialog.accept(self)

class akilliDiyaloglar(QDialog):
    def __init__(self, parent=None):
        super(akilliDiyaloglar, self).__init__(parent)
        self.yaziTipi = 'Comic Sans MS'
        self.metin = '
PythonDersleri.com
' self.label = QLabel(self.metin % self.yaziTipi) yatayKutu = QVBoxLayout() yatayKutu.addWidget(self.label) yaziTipiDugme = QPushButton('Yazı Tipini Değiştir') self.connect(yaziTipiDugme, SIGNAL('pressed()'), self.yaziTipiDegistir) yatayKutu.addWidget(yaziTipiDugme) self.setLayout(yatayKutu) self.setWindowTitle("Akıllı Diyaloglar") self.setWindowIcon(QIcon(simgeler + 'page.png')) def yaziTipiDegistir(self): diyalog = yaziTipiDiyalogu(self) diyalog.show() uygulama = QApplication([]) anaPencere = akilliDiyaloglar() anaPencere.show() uygulama.exec_()
Kodlarımızı çalıştırdığımızda karşımıza şöyle bir pencere gelecektir:
"Yazı Tipini Değiştir" butonuna tıkladığımızda ise pencere şu şekle gelecektir:
Buradaki kodlarımızda "Tamam" butonuna tıkladığımızda oluşan kabul durumunu kabul metodu ile bu diyalog içinde gerçekleştirdik. Bu sayede pencereyi kapattıktan sonra bellekten silebiliyoruz. İptal denildiğinde ise hiç bir değişiklik olmadan pencereyi kapatıp bellekten silebiliyoruz.

Akıllı diyaloglarla ilgili dikkatinizi çekmek istediğim bir nokta daha var. "Yazı Tipini Ayarla" penceremizi sürükleyip ana pencere üzerinden başka bir yere çektikten sonra ana pencere üzerinde "Yazı Tipini Değiştir" butonuna tekrar tıklamanıza yani ana pencere üzerinde işlem yapmanıza izin verir, bu durum akılsız diyaloglarda yoktur. Bu durum yapacağınız uygulamalara göre avantaj ya da dezavantaj oluşturabilir. Buna dikkat etmekte fayda var.

Akıllı diyaloglarda bir de kullanıcının yaptığı değişikliklerin kalıcı olmadığından bahsettik. Peki bu durum nasıl oluyor? Penceremize bazı uygulamalarda görmüş olabileceğiniz "Uygula" ve "Sıfırla" isminde iki buton daha eklememiz gerekiyor. Bu butonları da ekledikten sonra bütün butonları metotlara bağlamamız gerekiyor.
# Butonların eklenmiş hali
butonKutusu = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel | QDialogButtonBox.Apply | QDialogButtonBox.Reset)
butonKutusu.button(QDialogButtonBox.Apply).setText('Uygula')
# Butonun üzerindeki yazıyı "Uygula" yaptık
butonKutusu.button(QDialogButtonBox.Reset).setText('Sıfırla')
# Butonun üzerindeki yazıyı "Sıfırla" yaptık 


# Eklediğimiz butonların sinyallerini metotlara bağlıyoruz
self.connect(butonKutusu.button(QDialogButtonBox.Apply), SIGNAL('clicked()'), self.uygula)
self.connect(butonKutusu.button(QDialogButtonBox.Reset), SIGNAL('clicked()'), self.sifirla)


# Tüm butonlara ait metotların son hali de bu şekilde olmalı
def kabul(self):
        self.parent.yaziTipi = self.yaziTipiListesi.currentFont().family()
        self.parent.label.setText(self.parent.metin % self.parent.yaziTipi)
        QDialog.accept(self)

def uygula(self):
        self.parent.label.setText(self.parent.metin % self.yaziTipiListesi.currentFont().family())

def sifirla(self):
        self.parent.label.setText(self.parent.metin % self.parent.yaziTipi)
        self.yaziTipiListesi.setCurrentFont(QFont(self.parent.yaziTipi))

def reject(self):
        self.parent.label.setText(self.parent.metin % self.parent.yaziTipi)
        QDialog.reject(self)
Uygulamamıza yukarıdaki kodları da ekleyip çalıştırdığımızda bahsetmiş olduğumuz durumları gerçekleştirebilir hale gelmekteyiz. Pencerelere ait ekran görüntüsü de şu şekilde olacaktır:
Burada listeden yazı tipini seçtikten sonra Uygula diyerek kalıcı değişiklik yapmadan ve pencere kapanmadan yaptığımız değişiklikleri görebiliriz. Sıfırla diyerek de pencereyi açtığımızdaki ilk haline döndürebiliriz.


Kaynaklar:
http://zetcode.com/gui/pyqt4/dialogs/
Mustafa Başer - Python Kitabı

14 Ağustos 2014 Perşembe

PyQt Akılsız Diyaloglar

Akılsız diyaloglara neden akılsız diyalog denildiğinden çok bu diyalogların çalışma şekline değinelim. Akılsız diyaloglarda parçacıkların değerleri çağırıcı işlev tarafından ayarlanır ve yapılan değişiklikler de çağırıcı işlev tarafından yakalanır. Bu diyaloglar yalnızda parçacıkları ekranda görüntüleme işlevi görür. Ayrıca bu penceredeki işlem tamamlanmadan bu pencereyi çağıran ana pencerede başka bir işlem yapılamaz. Öncelikle açılan akılsız diyalog kapatılmalıdır.

Şimdi ana penceremiz üzerinde var olan bir label'ımızın içindeki yazının rengini bir alt pencere ile seçebileceğimiz bir örnek kod yazalım:
from PyQt4.QtGui import *
from PyQt4.QtCore import *

simgeler = 'D:/Simgeler/orange-moonlight-icons/png/64x64/'
# simgeler => http://dryicons.com/free-icons/preview/orange-moonlight-icons/

class yaziRengiDlg(QDialog):
    def __init__(self, parent=None):
        super(yaziRengiDlg, self).__init__(parent)
        izgara = QGridLayout()
        izgara.addWidget(QLabel('Yazı Rengi: '), 0, 0)
        self.yaziRengiListe = QComboBox()
        self.yaziRengiListe.addItems(('Red', 'Blue', 'Green', 'Yellow', 'Brown'))
        izgara.addWidget(self.yaziRengiListe, 0, 1)

        onayButonu = QPushButton('Tamam')
        redButonu = QPushButton('İptal')
        onayButonu.setDefault(True)

        butonKutusu = QHBoxLayout()
        butonKutusu.addWidget(onayButonu)
        butonKutusu.addWidget(redButonu)
        izgara.addLayout(butonKutusu, 1, 0, 1, 2)

        self.connect(onayButonu, SIGNAL('pressed()'), self.accept)
        self.connect(redButonu, SIGNAL('pressed()'), self.reject)

        self.setLayout(izgara)
        self.setWindowTitle('Yazı Rengini Seç')
        self.setWindowIcon(QIcon(simgeler + 'paint_brush.png'))

class akilsizDiyaloglar(QDialog):
    def __init__(self, parent=None):
        super(akilsizDiyaloglar, self).__init__(parent)
        self.yaziRengi = 'Blue'
        self.metin = 'PythonDersleri.com'
        self.label = QLabel(self.metin % self.yaziRengi)
        kutu = QVBoxLayout()
        kutu.addWidget(self.label)
        yaziRengiButonu = QPushButton('Yazı Rengini Değiştir')
        self.connect(yaziRengiButonu, SIGNAL('pressed()'), self.yaziRengiDegistir)
        kutu.addWidget(yaziRengiButonu)

        self.setLayout(kutu)
        self.setWindowTitle('Akılsız Diyaloglar')
        self.setWindowIcon(QIcon(simgeler + 'page.png'))

    def yaziRengiDegistir(self):
        diyalog = yaziRengiDlg()
        yaziRengiIndis = diyalog.yaziRengiListe.findText(self.yaziRengi)
        diyalog.yaziRengiListe.setCurrentIndex(yaziRengiIndis)
        if diyalog.exec_():
            self.yaziRengi = diyalog.yaziRengiListe.currentText()
            self.label.setText(self.metin % self.yaziRengi)

uygulama = QApplication([])
anaPencere = akilsizDiyaloglar()
anaPencere.show()
uygulama.exec_()
Bu programı çalıştırdığımızda ve "Yazı Rengini Değiştir" butonuna tıkladığımızda şu şekilde bir pencere gelecektir.

Burada da farklı olarak yazmış olduğumuz kodlardan bahsedelim.

4. Satır = Bu satırda simge dosyalarımın bulunduğu dizinin yolunu bir değişkene atadık. Programımızda kullandığımız simgeleri 5. satırda belirtmiş olduğumuz linkten ücretsiz temin edebilirsiniz.
30 ve 46. Satır = Bu satırlarda belirtilen QIcon nesneleri ile pencerelerin sol üst köşesinde görünen simgeleri belirledik.
51. Satır = Bu satır ile alt pencere açıldığında ana penceredeki yazının renginin seçili olarak alt pencerede gelmesini istedik.
18. Satır = Izgara pencerenin en altına yerleştirdiğimiz yatay buton kutumuzda "Tamam" butonunu ön tanımlı olarak belirledik. Bu tarz butonlar genellikle programların sağ alt köşesine yerleştirilir. Aynı hizanın sol tarafı boş kalmaktadır. Bunu sağlamak için 20. satırdan sonra butonKutusu.addStretch() kodunun eklenmesi yeterli olacaktır. Değişikliği farkedebilmek için pencerenin boyutunu artırmanız yeterli.
25 ve 26. Satır = Diyalog pencereleri kapatıldığında geri değer döndürürler. Bu değerler 0 ve 1'dir (accept ve reject). Biz buradan dönen 1 değerini "Tamam" butonuna atadık. Bunun anlamı o pencerede yapılan değişikliklerin uygulanacağı anlamına gelmektedir.


Kaynaklar:
-Mustafa Başer - Python Kitabı