30 Aralık 2013 Pazartesi

Django'da Hesaplama İşlemleri ve Q Nesnesi ile Karmşık Sorgulamalar

Merhaba Arkadaşlar,

Bu gün sizlere Django'nun işlerimizi kolaylaştırmak için bize sunduğu hesaplma işlemlerini ve Q nesnesinin ne işe yaradığını anlatacağım. Bu gün anlatacağım konular için hayali bir Kitap veritabanı olduğunu var sayalım. Hatta görünümümüz de aşağıdaki gibi olsun ki aklımız da soru kalmasın :

class Kitap(models.Model):
    turu=models.ForeignKey(Tur,verbose_name='Tür')
    adi = models.CharField(max_length=100,verbose_name='Adı')
    yazarlari = models.ManyToManyField(Yazar, verbose_name= 'Yazarları',blank=true)
    yayinevi = models.ForeignKey(Yayinevi, verbose_name='Yayinevi')
    sayfa_sayisi = models.IntegerField(verbose_name= 'Sayfa Sayısı', blank = true)
    basim_tarihi = models.DateField(verbose_name = 'Basım Tarihi', blank = true)
    fiyati = models.FloatField (verbose_name = 'Fiyatı', blank = true)
    
class Meta:
    ordering = ['adi']
    
def __unicode__(self):
    return u'%s' % (self.adi)

Şimdi sizlere hesaplama işlevlerinin bazılarını tabloya ve örnek kullanımlarını tabloda göstereyim:

İşlev AnlamıÖrnek
countSayma işlemini yapar.tür alanı 5 olan kitapların sayısını bulalım.
>>>Kitap.objects.filter(turu=5).count()
AvgOrtalamayı bulur yazarlar alanı 1 olan kitapların ortalama sayfa sayısını bulalım:
>>> from django.db.models import Avg
>>>Kitap.objects.filter(yazarlari=1).aggregate(Avg('sayfa_sayisi'))
MaxEn büyüğünü bulur En pahalı kitabın fiyatını bulalım:
>>> from django.db.models import Max
>>>Kitap.objects.aggregate(Max('fiyati'))
MinEn küçüğünü bulur Sayfa sayısı en az olan kitabın sayfa sayısını bulalım:
>>> from django.db.models import Min
>>>Kitap.objects.aggregate(Min('sayfa_sayisi'))
SumToplamını bulur yazar alanı 1 olan kitapların toplam sayfa sayısını bulalım:
>>> from django.db.models import Sum
>>>Kitap.objects.filter(yazarlari=1).aggregate(Sum('sayfa_sayisi'))



Şimdi de Django veritabanı sorgulamalarında kullanabileceğimiz alan irdelemelerini ve anlamlarını tablolamak istiyorum:

İrdeleme Analmı
exactSorgulamada tam eşleşmeyi arar.
iexactDuyarsız eşleme
containsİçerisinde belirlenen alt kelime grubunun bulunduğu eşlemeleri yapar.
icontainsİçerisinde belirlenen alt kelime grubunun bulunduğu eşlemeleri duyarsız yapar.
inBir listede bulunup bulunmadığına bakar.
gtDaha büyük (>)
gteDaha büyük ya da eşit
ltDaha küçük (<)
lteDaha küçük ya da eşit
statrwith'ile başlayan'
istatrwithduayrsız 'ile başlayan'
enswith'ile biten'
ienswithduyarsız 'ile biten'
rangebelirli aralıkta bulunan
yearYıl araması yapar
montAY araması yapar
dayGün araması yapar

Q Nesnesi İle Karmaşık Sorgulama

Sorgularımızda filter() işlevine verdiğimiz parametreler AND ile kullanılır. Örneğin sayfa sayısı 350'den az, fiyatı 18 tl'den fazla olan kitapları bulmak için şöyle bir sorguya ihtiyacımız olacaktır.

Kitap.objects.filter(sayfa_sayisi__lt= 350, fiyati__gt=18)

Bu sorgunun ham SQL sorgusu da şöyledir:

SELECT *
FROM kitap_kitap 
WHERE sayfa_sayisi <350 AND fiyati > 18 

Eğer sorguları OR  ile birleştirmek istiyorsak Q nesnesini kullanmamız gerekir.Diyelim ki sayfa sayısı 350'den az veya fiyatı 20 TL'den fazla olan kitapları arayalım. Eğer SQL kullansaydık sorgumuz söyle olacaktı 

SELECT *
FROM kitap_kitap 
WHERE sayfa_sayisi <350 OR fiyati > 20 

Bu sorguyu Django nesnelerini kullanarak şöyle yaparız:

>>> from django.db.models import Q 
>>> sorgu = Q(sayfa_sayisi__lt=350) | Q(fiyati__gt=20)
>>> Kitap.objects.filter(sorgu)


Ham SQL Sorgusu İle Sorgulama Yapma 

Bazen model sorgulamaları yetersiz kaldığında ham SQL sorgularına da ihtiyaç duyabiliriz. Django ham SQL sorgusu yapmayı engellemez. Örnek bir ham SQL sorgusu :


>>> for kitap in Kitap.objects.raw('SELECT * FROM kitap_kitap')
...     print kitap


Bu kullanım Kitap.objects.all() sonucu ile aynıdır. 


Referanslar :
  1. https://docs.djangoproject.com/en/dev/ref/models/querysets/
  2. BAŞER, Mustafa (2013). Django
  3. http://www.slideshare.net/Counsyl/efficient-djangoquery-setuse

26 Aralık 2013 Perşembe

Django'da Veritabanı-2

Merhaba Arkadaşlar,

Geçen hafta Django'da veri tabanınına giriş yapmıştık. Veri tabanına verinin nasıl girildiğini ve verinin nasıl alındığını anlatmıştım. Bu hafta ise sorgulama, güncelleme, sıralama ve silme gibi veritabanı işlemlerini anlatmak istiyorum.

VERİ SORGULAMA 

Geçen hafta bir tablodaki tüm veriyi alabilmek için objects.all() özelliğinin nasıl kullanıldığını gördük. Peki bir tablodaki bütün veriden ziyade sadece belli özelliklere sahip olan veriyi almak için ne yapmalıyız? Bunun için yani verileri filtrelemek için ise objects.filter() özelliğini kullanırız. Örneğin geçen haftaki örneğimizden adı Ali olan öğretim elemanlarını filtrelemek istersek :

>>> ogretimelemanlari = OgretimElemani.objects.filter(adi='Ali')
>>> ogretimelemanlari
[<OgretimElemani:Taş, Ali>]

Burada tam eşleme yapılmıştır ve büyük-küçük harf duyarlılığı vardır. Eğer birden fazla özelliği filtrelemek istiyorsak objects.filter( filtre1, filtre2,...) şeklinde kullanabiliriz.

Soyadında 'k' harfi bulunduran öğretim elemanlarını filtrelemek istersek:

>>> ogretimelemanlari = OgretimElemani.objects.filter(soyadi__contains='k')
>>> ogretimelemanlari
[<OgretimElemani:Kaya, Hakan>,<OgretimElemani:Keser, Mustafa>,<OgretimElemani:Kaya, Mustafa>]

Django'nun bir diğer kullanışlı özelliği de filtrelerin birlikte kullanılmasıdır. Örneğin adında adında 'a' harfi olup da soyadında 'a' harfi olmayanları filtrelemek istersek :

>>> ogretimelemanlari = OgretimElemani.objects.filter(adi__contains='a').exclude(soyadi__contains='a')
>>> ogretimelemanlari
[<OgretimElemani:Keser, Mustafa>]

Bir modeldeki alanları ve içeriklerini values özelliği ile alabiliriz. Örneğin bir derse ve bir öğrenciye ait bilgileri ekrana bastıralım :

>>> alan1 = Ders.objects.values()[1]
>>> for a in alan1:
...     print a ,':', alan1[a]
...
ogretim_elemani_id : 3
kodu : BIM333
id : 3
tanimi :
adi : Network Programlama

>>> alan2 = Ogrenci.objects.values()[0]
>>> for b in alan2:
...     print b ,':', alan2[b]
...
soyadi : Keskin
id : 1
numarasi : 1
adi : Mehmet

Peki ya yapacağımız sorguda dilimleme yapmak istersek ne yapmalıyız? Yani yapacağımız sorguda belli sayıda satır almak istiyorsak ne yapmalıyız? Örneğin veritabanımızdaki ilk 20 öğrenciyi alalım:

>>> ilk20ogrenci = Ogrenci.objects.all()[0:20]

Burada yapılan işlem, önce tüm öğrencileri sorgulayıp daha sonra ilk 20 öğrenciyi almak değil; sorgulama yaparken ilk 20 satırı almaktır. Böylece performansı arttırmış, bellek kullanımını azaltmış oluruz. Aynı sonucu aşağıdaki gibi de elde edebiliriz ama bu sırada performans düşer, bellek kullanımı da artmış olur. Bu yüzden aşağıdaki kullanımdan kaçınmalıyız :

>>> ogrenciler = Ogrenci.objects.all()
>>> ilk20ogrenci = ogrenciler[0:20]

VERİ GÜNCELLEME

Django'da veri güncelleme de oldukça basittir. Önce nesneyi alıp daha sonra istediğimiz özelliğini değiştiririz. Örneğin OgretimElemani tablomuzdan adı Mustafa soyadı Kaya olan öğretim elemanının telefon numarasını göncelleyelim :

>>> ogrelm = OgretimElemani.objects.filter(adi='Mustafa',soyadi='Kaya')[0]
>>> ogrelm.telefonu='123456789'
>>> ogrelm.save()


VERİ SIRALAMA

Django'da da diğer dillerde olduğu gibi herhangi bir sıralama yapılmamışsa sorgular rastgele gelir.Yani SQLite verinin eklenme sırasına göre sıralar. Django'da sıralamalar objects.order_by() özelliği ile yapılmaktadır. Veritabanımızdaki öğretim elemanlarını isimlerine göre sıralayalım :


>>> ogretimelemanlari = OgretimElemani.objects.order_by('adi')

>>> ogretimelemanlari
[<OgretimElemani: Taş, Ali>, <OgretimElemani: Kaya, Hakan>, <OgretimElemani: Ke
ser, Mustafa>, <OgretimElemani: Kaya, Mustafa>]

Eğer sıralamayı tersten yapmak istiyorsak da sıralama alanının önüne eksi(-) işareti koyarız :

>>> ogretimelemanlari = OgretimElemani.objects.order_by('-adi')

>>> ogretimelemanlari
[<OgretimElemani: Keser, Mustafa>, <OgretimElemani: Kaya, Mustafa>, <OgretimElem
ani: Kaya, Hakan>, <OgretimElemani: Taş, Ali>]

Çoğu zaman sorgulamaların ön tanımlı bir alana göre sıralanmasını isteyebiliriz. Örneğin Öğretim elemanlarını, sıralama ölçütü vermediğimiz durumlarda soyadına göre listelemek isteyebiliriz. Bunu yapmak için models.py dosyamızı aşağıdaki gibi tanımlamamız yeterli olacaktır. Hatırlatmakta fayda var diye tekrarlamak istiyorum. .py uzantılı dosyalarımızda yaptığımız herhangi bir değişikliği Django kabuğunda da görmek istiyorsak kabuğu tekrardan başlatmamız gerekir.

class OgretimElemani(models.Model):
    adi = models.CharField(max_length =50)
    soyadi = models.CharField(max_length =50)
    telefonu = models.CharField(max_length =10,blank=True)
    e_posta_adresi = models.EmailField(blank = True)

    def __unicode__(self):
        return u'%s, %s' %(self.soyadi,self.adi)
    
    class Meta:
        ordering =['soyadi']

Şimdi de Django kabuğunu yeniden başlatıp öğreitm elemanlarını listeleyelim:

>>> from yonetim.models import *

>>> OgretimElemani.objects.all()
[<OgretimElemani: Kaya, Hakan>, <OgretimElemani: Kaya, Mustafa>, <OgretimElemani
: Keser, Mustafa>, <OgretimElemani: Taş, Ali>]

>>>

VERİ SİLME

Nesneleri silmek için delete() özeliğini kullanırız. Ali Taş öğretim görevlisini silelim :

>>> ogrelmsil = OgretimElemani.objects.get(soyadi ='Taş', adi='Ali')
>>> ogrelmsil.delete()
 
>>> OgretimElemani.objects.all()
[<OgretimElemani: Kaya, Hakan>, <OgretimElemani: Kaya, Mustafa>, <OgretimElemani
: Keser, Mustafa>]
>>>

Burada öğretim elemanını almak için objects.get() özelliğini kullandık. Ama bu özelliği kullanırken dikkatli olmalıyız. Çünkü veri tabanımızda olmayan bir veriyi almak istersek hata yükselir. Django tabloları oluştururken her satıra tekil bir ID alanı oluşturur. O halde silme işlemi yaparken bı ID numarasını kullanmak daha mantıklı olacaktır. ID numarasına nesnenin id  yada pk özelliğinden arişebiliriz. Şimdi bir öğretim elemanı ekleyelim.

>>> ogrelm = OgretimElemani(adi='Fatih', soyadi ='Çelik')
>>> ogrelm.pk

Kaydedilmeden önce ID numarası yoktur. Şimdi kaydedip ID numarasını öğrenip ona göre silelim :

>>> ogrelm.save()
>>> ogrelm.pk
6
>>> ogrelm.id
6
>>> OgretimElemani.objects.all()
[<OgretimElemani: Kaya, Hakan>, <OgretimElemani: Kaya, Mustafa>, <OgretimElemani
: Keser, Mustafa>, <OgretimElemani: Çelik, Fatih>]
>>> OgretimElemani.objects.filter(id=6).delete()
>>> OgretimElemani.objects.all()
[<OgretimElemani: Kaya, Hakan>, <OgretimElemani: Kaya, Mustafa>, <OgretimElemani
: Keser, Mustafa>]

>>>

Daha ayrıntılı sorgulama seçeneklerine ve model alan tiplerine  buradan ulaşabilirsiniz.

Referanslar :
  1. https://docs.djangoproject.com/en/dev/
  2. BAŞER, Mustafa (2013). Django

15 Aralık 2013 Pazar

Django'da Veritabanı-1

Merhaba Arkadaşlar

Şimdiye kadar Django'nun nasıl çalıştığını öğrendik. Bildiğiniz gibi dinamik web uygulamaları verileri veritabanında tutarlar. Bu blogumda da sizlere Django'nun veritabanı bağlantısının nasıl yapıldığını ve veritabanı temel fonksiyonlarının nasıl kullanıldığını basit bir öğrenci bilgi sistemi örneği üzerinden anlatmak istiyorum. Burada her ne kadar SQL komutu işlemeyeceksek de, SQL komutlarını bilmemiz konuya daha da hakim olmamızı sağlayacaktır.

Django'nun veritabanı uygulamaları için kullanıcılarına sunduğu en büyük kolaylık; kullanıcının  SQL tablolarını oluşturmaması ve sorgularla uğraşmaması olabilir diye düşünüyorum. Biraz garip geldiğinin farkındayım. Gelin birlikte bakalım.

Django ön tanımlı olarak PostgreSQL, MySQL, SQLite ve Oracle desteği ile gelir. Veritabanı yapılandırması proje klasöründe bulunan settings.py dosyası içerisinde yapılır. Bu dosyanın DATABASES bölümü aşağıdaki gibidir:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': '',                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}
  (Blog sayfasının genişliğinden dolayı yazıda kaymalar olmuş olabilir.)

Hangi veritabanı sistemini kullanıyorsak bunu ENGINE parametresinde belirtiriz. Bu parametreler: postgresql_psycopg2, mysql, sqlite3 ya da oracle olabilir. Ayrıca django.db.backends. ön takısını kullanırız. Bağlantının nasıl yapıldığını öğrendiğimize göre artık örneğimize başlayabiliriz. Örneğimiz basit bir okul veritabanı örneği olacaktır. Okulumuzda öğretim elemanı, ders ve öğrenci sınıflarını tanımlayacağız. Projemizin adı okul olsun. Projelerimizi oluşturduğumuz konuma gelerek yeni bir proje oluşturalım. Bunu daha önceki bloglarımdan da hatırlayacağınız üzre şöyle yapıyorduk:

> C:\Python27\python.exe C:\Python27\Lib\site-packages\django\bin\django-admin.py startproject okul 

SQLite bir sunucu sistemi gereksinimi olmadan çalışan veritabanı sistemidir. Böylelikle veritabanı sunucusu yönetimine gereksinim duymadan işimizi yürütebiliriz. üstelik farklı yerlerde geliştirme yapıyorsak, veritabanı dosyasıda proje klasöründe olacağından taşıma sorunumuz da olmayacaktır.

Şimdi projemizin veritabanı yapılandırmasını yapmak üzere proje klasörümüzdeki settings.py dosyasını açalım ve aşağidaki satırları dosyanın başına ekleyelim.

import os.path
konum = os.path.dirname(__file__)
ustDizin = os.path.split(konum)[0]

Daha sonra DATABASES değişkenini aşağıdaki gibi yapılandırlaım:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': os.path.join(ustDizin,'var/okul.db'),                      # Or path to database file if using sqlite3.
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}
 (Blog sayfasının genişliğinden dolayı yazıda kaymalar olmuş olabilir.)

SQLite için NAME parametresine veritabanı dosyasının tam patikası yazılır. Eğer dosya yok ise oluşturulur. Şimdi de Veritabanı dosyasının oluşturulacağı dizini oluşturalım. Bunu da komut satırından şöylece yapalım:

> mkdir C:\...\DjangoProjeleri\okul\var

Projeler genellikle karmaşık yapıya sahiptirler. Bu karmaşıklığın üstesinden gelebilmek için Django'da uygulamalar açılır. Biz ilk olarak yonetim uygulamasını geliştireceğiz. Bu uygulamada basit olarak öğretim elemanı, ders, öğrenci ve öğrencilerin aldıkları derslerigireceğiz. Artık proje klasörümüze girerek uygulamamızı oluşturalım :

C:\...\DjangoProjeleri > cd okul
C:\...\DjangoProjeleri\okul > C:\Python27\python.exe manage.py startapp yonetim

Yukardaki komut ile yonetim adında bir klasör ve içerisine temel uygulama dosyalarımız oluşturulur. Şimdi sıra uygulamamızı projemize eklemede, bu amaçla C:\...\DjangoProjeleri\okul\okul\settings.py dosyasını açıp  INSTALLED_APPS değişkenine yonetim uygulamamızı ekleyelim.

settings.py
                                                                                                                                
INSTALLED_APPS = (
    #'django.contrib.auth',
    #'django.contrib.contenttypes',
    #'django.contrib.sessions',
    #'django.contrib.sites',
    #'django.contrib.messages',
    #'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    # 'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'yonetim',
)
                                                                                                                                

Django'da SQL tablolarının ve sorguların yapılabilmesi için bazı tanımlamalar yapmamız gereklidir. Yani burada sadece tablolar ve bu tablolardaki alanları tanımlıyoruz. Bu tanımlamalar da model diye adlanrılır.
Artık modelimizi oluşturabiliriz. Bunun için C:\...\DjangoProjeleri\okul\yonetim\models.py açıp aşağıdaki tanımlamaları yapalım:
models.py
from django.db import models

class OgretimElemani(models.Model):
    adi = models.CharField(max_length =50)
    soyadi = models.CharField(max_length =50)
    telefonu = models.CharField(max_length =10,blank=True)
    e_posta_adresi = models.EmailField(blank = True)
 
class Ders(models.Model):
    kodu = models.CharField(max_length =10)
    adi = models.CharField(max_length =50)
    ogretim_elemani = models.ForeignKey(OgretimElemani)
    tanimi = models.EmailField(max_length=1000, blank = True)


class Ogrenci(models.Model):
    numarasi = models.IntegerField()
    adi = models.CharField(max_length =50)
    soyadi = models.CharField(max_length =50)
    aldigi_dersler = models.ManyToManyField(Ders)
 

Herhangi bir alanın seçeneğe bağlı olarak girilmesini sağlamak için, o alanı tanımlarken blank= True argümanını eklememiz gerekmektedir.  Ayrıca Ogrenci modelindeki
aldigi_dersler = models.ManyToManyField ( Ders ) satırı ile de öğrencinin aldığı ders tablosu oluşturulacaktır. Tabloları oluşturmadan önce modellerimizde ve diğer yapılandırmalarımızda bir hata olup olmadığını denetleyelim. Bunun için aşagıdaki komut satırını yazalım:


> C:\Python27\python.exe manage.py validate

Eğer sonuç  0 errors found herhangi bir sorun yok demektir. Artık tablolarımızı oluşturabiliriz. Bunun için ise aşağıdaki kod satırı yeterli olacaktır:


> C:\Python27\python.exe manage.py syncdb
Creating tables ...
Creating table yonetim_ogretimelemani
Creating table yonetim_ders
Creating table yonetim_ogrenci_aldigi_dersler
Creating table yonetim ogrenci
Installing custom SQL ...
Installing indexes ...
Installed 0 object(s) from 0 fixture(s)

Tablolarımız oluşturuldu. Sıra tablolara veri eklemede.   Bunun için Django kabuğunu (shell) açalım:

> C:\Python27\python.exe manage.py shell

VERİ EKLEME 
Önce birkaç öğretim elemanı ekleyelim:

>>> from yonetim.models import *
>>> ogrelm1 =OgretimElemani(adi='Hakan',soyadi='Kaya',telefonu='123456789',e_posta_adresi='hakankaya@kaya.com')
>>> ogrelm1.save()
>>> ogrelm2 =OgretimElemani(adi='Ali',soyadi='Taş',telefonu='987123456',e_posta_adresi='alitas@tas.com')
>>> ogrelm2.save()
>>> ogrelm3 =OgretimElemani(adi='Mustafa',soyadi='Keser',telefonu='',e_posta_adresi='')
>>> ogrelm3.save()
>>> ogrelm4 =OgretimElemani(adi='Mustafa',soyadi='Kaya',telefonu='654789123',e_posta_adresi='')
>>> ogrelm4.save()

Kayıtların veritabanına işlenmesi için mutlaka save() fonksiyonunu kullanmamız gerekir. Aksi halde tanımlanma yapılmış olur ama veri tabanına eklenmez. Şimdi veritabanına eklediğimiz bir veri satırına ulaşmaya çalışalım.

>>> ogrelm1
<OgertimElemani: OgretimElemani object>

Gördüğünüz gibi pek de açıklayıcı bir bilgi vermedi bize. Daha düzgün bir görünüm için modelin __unicode__() işlevini tanımlamamız gerekiyor. OgretimElemani modelimizi aşağıdaki gibi güncelleyelim ve kaydedelim.

...
class OgretimElemani(models.Model):
    adi = models.CharField(max_length =50)
    soyadi = models.CharField(max_length =50)
    telefonu = models.CharField(max_length =10,blank=True)
    e_posta_adresi = models.EmailField(blank = True)

    def __unicode__(self):
        return u'%s, %s' %(self.soyadi,self.adi)
...

Değişikliklerin etkin olabilmesi için Django kabuğunun (shell'in) yeniden başlatmalıyız.

Bir modeldeki tüm veriyi almak için object.all() özelliğini kullanabiliriz:

>>> from yonetim.models import *
>>> ogretimelemanlari = OgretimElemani.objects.all()
>>> ogretimelemanlari
[<OgretimElemani:Kaya, Hakan>,<OgretimElemani:Taş, Ali>,
<OgretimElemani: Keser, Mustafa>,<OgretimElemani:Kaya, Mustafa>]


Siz de diğer modellerin görünümünde bize bilgi vermesi için __unicode__() işlevlerini istediğiniz gibi tanımlayabilirsiniz. Şimdi bir ders ekleyelim ve dersin öğretim elemanının Hakan Kaya yapıp kaydedelim.

>>>ders1 = Ders(kodu='BIM101', adi ='programlamaya giriş')
>>>ders1.ogretim_elemani = ogretimelemanlari[0]
>>>ders1.save()

Bu işlemi aşağıdaki gibi tek de yapabiliriz:

>>>ders1 = Ders(kodu='BIM101', adi ='programlamaya giriş', ogretim_elemani= ogretimelemanlari[0])
>>>ders1.save()

Şimdi iki tane daha ders ile bir öğrenvi ekleyip öğrenciye eklediğimiz dersleri ekleyelim:

>>>ders2 = Ders(kodu='BIM222', adi ='Internet Programlama', ogretim_elemani= ogretimelemanlari[1])
>>>ders1.save()
>>>ders3 = Ders(kodu='BIM333', adi ='Veri yapıları', ogretim_elemani= ogretimelemanlari[2])
>>>ders1.save()
>>>ogr1 = Ogrenci(numarasi= 123, adi ='Mehmet', soyadi='Keskin')
>>>ogr1.save()
>>>ogr1.aldigi_dersler.add(ders2,ders3)


Herhangi bir öğrencinin aldığı derslere de şu şekilde bakabiliriz:

>>>ogr1.aldigi_dersler.all()
[<Ders: BIM222: Internet Programlama>,<Ders: BIM333: Veri yapıları>]

Ve aldığı herhangi bir dersini de silebiliriz:

>>>ogr1.aldigi_dersler.remove(ders3)
>>>ogr1.aldigi_dersler.all()
[<Ders: BIM222: Internet Programlama>]

Eğer tüm derslerini silmek istersek de aldigi_dersler.clear() özelliğini kullanabiliriz.

Referanslar :
  1. https://docs.djangoproject.com/en/dev/
  2. BAŞER, Mustafa (2013). Django

5 Aralık 2013 Perşembe

Django'da Şablonlar 2


     Merhaba Arkadaşlar,

     Django'da Şablonlar adlı bloğumda sizlere şablonları ve şablon kullanımını anlatmıştım. Bu hafta ise şablonları kullanırken Django'nun bize sunduğu kolaylığı anlatmak istiyorum.

     Geçen hafta yaptığımız uygulamada öğrencilerin notlarını ve başarı durumlarını gösteren bir web sayfası şablonuyla çalışmıştık. Ve views.py dosyamız aşağıdaki gibiydi.

views.py
# -*- coding: utf-8 -*-

from django.http import *
from django.template import Template, Context



def notlar(request):
    ogrenciler =((u'Kadir',u'Guler',40,85,75,True),
                 (u'Ahmet',u'Baba',22,58,36,False),
                 (u'Suzan',u'Keskin',65,75,95,True),
                 (u'Ufuk',u'Hakan',45,15,36,False),
                 (u'Hayrettin',u'Öğüt',50,69,50,True),
                 (u'Mehmet',u'Kaan',42,85,25,True),
                 (u'Ayşe',u'Sanem',35,90,75,True),
            )    s=Template(open('C:...\\deneme\deneme\\sablonlar\\notlar.html').read()) (1)

    b = Context({'ogrenciler' : ogrenciler})      (2)

html = s.render(b) (2)

return HttpResponse(html) (3)


Yukardaki kod satırlarını inceledikten sonra : "Bütün herşeyi ben yaptım! Hani kolaylık bunun neresinde?" der gibiyiz. Aslında geçen hafta konuya tam anlamıyla hakim olabilmek için herşeyi uzun uzadıya yazmak istedim. Şimdi ise Django'nun bizlere sağladığı kolaylıklara bakalım.

Yukarıda yazdığımız kodlar sırasıyla şu işlemleri yapıyor:
  1. Şablonu çağırma
  2. Veriyi bağlam haline getirmek
  3. Bunu yorumlatmak
Şimdi saydığımız şu üç işlemi Django'nun bize sunduğu kolaylılardan biri olan render_to_response() işlemi ile yapalım. render_to_response() işlevi yukarda saydığım şablon çağırma, veriyi bağlam haline getirme ve yorumlama işlemlerinin tamamını tek satırda yapmamı sağlıyor. Bunu aşağıdaki şekilde yapalım ve aynı işlemi daha az kod satırıyla yaptığımızı görelim.

views.py
...
from django.shortcuts import render_to_response

def notlar(request):
    ogrenciler =((u'Kadir',u'Guler',40,85,75,True),
                 (u'Ahmet',u'Baba',22,58,36,False),
                 (u'Suzan',u'Keskin',65,75,95,True),
                 (u'Ufuk',u'Hakan',45,15,36,False),
                 (u'Hayrettin',u'Öğüt',50,69,50,True),
                 (u'Mehmet',u'Kaan',42,85,25,True),
                 (u'Ayşe',u'Sanem',35,90,75,True),
            )
    
    return render_to_response('notlar.html',{'ogrenciler':ogrenciler})
...

Aynı zamanda Django'nun bizlere sunduğu bir diğer kolaylık ise; görünüm altında tanımlanmış nesne isimlerinden oluşan bir sözlük döndürmesidir. Yani  {'ogrenciler': ogrenciler} ile belirtilen sözlüğe locals() işlevi ile ulaşabiliriz. Bu işlev, görünüm içerisindeki nesneyi şablonları yorumlamaya gönderirken karışıklık olmasını önler.

    Bir şablon dizininde alt dizinler de bulunabilir. Bu alt dizinlerdeki şablonları kullanırken, şablon isminden önce alt dizinin adı yazılır. Örneğin yukarıdaki örneğimizde  C:...\deneme\deneme\sablonlar gibi bir şablon dizinimiz vardı. Bu dizine  C:...\deneme\deneme\sablonlar\alt_sablonlar gibi bir alt dizindeki şablonu görünümümüzde kullanmak için render_to_response() işlevimizi aşağıdaki gibi kullanırız.

 
return render_to_responde('alt_sablonlar\yeni_sablon.html',locals())

İÇ İÇE ŞABLONLAR

Artık web sayfaları o kadar karmaşık yapılıyor ki, bir sayfanın tamamının tek bir şablon ile oluşturulması neredeyse imkansız bir hal aldı. Üstelik web sayfalarının çoğu ortak bileşenlerden oluşmaktadır. Örneğin sayfanın solunda ya da üst bölümünde gezinmeyi sağlayan bölümler bulunmaktadır. Bu gezinti bölümleri her sayfada aynı olduğuna göre bu kısımları tüm şablonlara yazmaya gerek yoktur. O halde bir kereliğine hazırlayıp istediğimiz şablon içerisinden çağırmamız çok daha kolay olacatır. Bu işlemi include etiketi ile yaparız. Örneğin geçen hafta yaptığımız örneğe alt ve üst bilgi ekleyelim. Bunu da farklı iki şablonu çağırarak yapalım.

Önce projemizde kullanacağımız şablonları depoladığımız  C:\...\deneme\sablonlar konumana icerilen_sablonlar diye bir alt dizin oluşturalım. Buraya alt ve üst bilgi için oluşturacağımız şablonları ekleyeceğiz. Şimdi de buraya ust_bilgi.html diye bir şablon ekleyelim. İçeriği aşağıdaki gibi olsun.

ust_bilgi.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 TRANSITIONAL//EN">
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title> {{sayfa_basligi}} </title>
</head>
<body>
     Üst bilgi...
     
<hr>     

Ve alt_bilgi.html diye bir şablon oluşturalım. Bu da sayfanın altında bilgi veren bir şablon olsun. İçeriği de :

alt_bilgi.html
<hr>
Alt bilgi...

<br> Erişim zamanı: {{simdiki_zaman}}

</body>
</html>

Şimdi de notlar.html şablonunu yukarda yazdığımız iki şablonu içerecek şekilde değiştirelim. Yukarda da söylediğim gibi bu işlemi include etiketi ile yapacağız. Şöyle ki:

notlar.html
{% include "icerilen_sablonlar/ust_bilgi.html" %}

    <table border="1">
        <tr><th> Sıra </th><th> Adı </th>  <th> Soyadı </th> 
        <th> Vize </th> <th> Ödev </th><th> Final </th><th> Başarı Durumu </th><tr>
        {% for ogr in ogrenciler %}            
            <tr><td>{{forloop.counter}}</td>
            <td>{{ogr.0}}</td>
            <td>{{ogr.1}}</td>
            <td>{{ogr.2}}</td>
            <td>{{ogr.3}}</td>
            <td>{{ogr.4}}</td>
            <td>{% if ogr.5 %} BAŞARILI
                {% else %}     BAŞARISIZ
                {% endif %}
            </td></tr>
        {% endfor %}
    </table>
    
{% include "icerilen_sablonlar/alt_bilgi.html" %}

Şimdi de sıra ust_bilgi.html ve altbilgi.html şablonlarında tanımladığımız sayfa_basligi ve simdiki_zaman değişkenlerini görünümümüzde tanımlamamıza geldi. Bunu da views.py dosyasındaki notlar() işlevine şöylece ekleyelim.

views.py
...
def notlar(request):
    ogrenciler =((u'Kadir',u'Guler',40,85,75,True),
                 (u'Ahmet',u'Baba',22,58,36,False),
                 (u'Suzan',u'Keskin',65,75,95,True),
                 (u'Ufuk',u'Hakan',45,15,36,False),
                 (u'Hayrettin',u'Öğüt',50,69,50,True),
                 (u'Mehmet',u'Kaan',42,85,25,True),
                 (u'Ayşe',u'Sanem',35,90,75,True),
            )

    sayfa_basligi =u'NOT LİSTESİ'
    simdiki_zaman= time.ctime()
    return render_to_response('C:\\...\\deneme\\deneme\\sablonlar\\notlar.html', locals())
...



Artık aşağıdaki adrese gittiğimizde şablonları tek bir sayfada görebildiğimizi göreceksiniz.
http://localhost:8000/notlar

Ve sayfa görüntümüz de şu şekilde olacaktır:




















2 Aralık 2013 Pazartesi

Django'da Şablonlar-1


Merhaba arkadaşlar,

Geçen hafta sizlerle Django'da görünüm oluşturmayı ve bu görünüme adres (url) hazırlamayı öğrendik. Bu hafta ise Django'da  şablonları öğrenelim istedim. Şimdiye kadar tasarımı dahi kodlamayla yaptık. Yani bir gün yaptığımız sayfanın görünümünü değiştirmek istersek; bu değişimi Python kodlarını düzenleyerek yapmamız gerekir. Ama bir şablon oluşturarak kodlama ve tasarımı birbirinden ayırabiliriz. Bunun için Django şablon sistemini kullanalım. Django'nun şablon sistemini anlamak için etkileşimli kabukta biraz çalışalım. Bunun için komut satırına aşağıdaki komutu yazarak Django kabuğunu açalım.

C:\djangoprojeleri\deneme > C:\Python27\python.exe manage.py shell

Şimdi basit ama şablon kavramını kavramamıza yardımcı olacak bir örnek yapalım.

>>>from django import template
>>>x= template.Template("Dersin Adı {{ adı }}.")
>>>y= template.Context({'adı':'Django'})
>>>print x.render(y)
Dersin Adı Django.


Burada şablon x nesnesine şablon, y nesnesine ise bağlam diyoruz.Bağlam içerisindeki {{ ile }} arasındaki değişkenlere de bağlam değişkeni diyoruz. x.render(y) işlemine ise x şablonunun y bağlamı ile yorumlanması diyoruz. Bir şablon nesnesi birden fazla bağlam ile yorumlanabilir.

Şimdi bir şablona basit bir şekilde bir Python sözlüğünü aktaralım:

x = template.Template("""<html><head><title>{{ baslik }}</title>
</head>
<body>
<br>Dersin Kodu: {{ kod}}
<br><b>Dersin Adi:</b>{{ adi }}
<br>Dersin sinifi: {{ sinifi}}
</body>
</html>""")

>>> veri = {"baslik":"Ders bilgileri","kod":"BIM222","adi":"Django","sinifi":"B7",}

>>> y = template.Context(veri)

>>> print x.render(y)
<html><head><title>Ders bilgileri</title>
<body>
<br>Derd Kodu: BIM222
<br><b>Ders Adi:</b> Django
<br>Dersin sinifi: B7
</body>
</html>

Eğer bağlamda olmayan nesne ya da nesne özelliklerini kullanırsak Python'daki gibi hata vermez sadece boş olduğunu gösterir.

Yukarıda sadece şablona bağlamlar ile veri aktardık ve şablon içerisinden bu veriye ulaştık. Ancak web uygulamalarında şablonlar içerisinde bir takım temel programlama etiketlerine ihtiyaç duyarız.Bunlardan en çok kullanılan iki tanesini inceleyelim.

if / else ETİKETİ

{% if %}  etiketi diğer programlama dillerinde olduğu gibi burda da koşulları kontrol etmek için kullanılır.
Temel yapısı şöyledir:
{% if   ___ %}
           ...
{% elif___  %}
           ...
{% else  %}
           ...
{% endif  %}

for ETİKETİ
Şablon içerisinde kullanabileceğimiz tek döngü for döngüsüdür. Örneğin takım kadrosunda bulunan futbolcuların listelenmesi için aşağıdaki gibi bir döngü kullanırız.


<ul>
{% for futbolcu in kadro %}
    <li>{{ futbolcu.isim}}</li>
{% endfor %}
</ul>


for döngüsü ile tersten de iterasyon yapılabilir. Bunun için {% for obj in list reversed %} yapısı 
kullanılır. Bazı önemli for döngüsü değişkenleri şunlardır:


forloop.counter        döngü sayacı değişkenimizdir (1'den başlar)
forloop.counter0       döngü sayacı değişkenimizdir (0'dan başlar)
forloop.revcounter     Sayacı tersten almak içim (1'de sonlanır)
forloop.revcounter0    Sayacı tersten almak içim (0'da sonlanır)
forloop.first          Döngünün başını kontrol etmek için kullanılır
forloop.last           Döngünün sonunu kontrol etmek için kullanılır


Django şablonları içerisinde  karşılaştırmaları or, and, not, in gibi işleçlerle birleştirebiliriz. Kullanımı Python'daki gibidir.

FİLTRELER
Django şablonları içerisinde kullanılabilecek birçok filtre ile birlikte gelir. Ama hepsini anlatma şansım malesef yok. Bu yüzden en çok kulanılanlarını açıklamaya çalışacağım. Bir çok filtre argüman almamakla birlikte genel bir kullanım şekli vardır. Şöyle ki:

{{bağlam_değişkeni | filtre : filtre_argümanı }}

add 
İki argümannı toplar. Örneğin;  {{ değer | add : "2"}}

capfirst
Verilen değerin ilk harfini büyük harfe çevirir.Örneğin; {{ "django" | capfirst }} çıktısı "Django" olur.

cut
Verilen string değişkeninden silinmesi istenen değerler silinir. Örneğin  {{"   Ahmet Amca'nın evi    "| cut :" "}}
"AhmetAmca'nınevi " değerini döndürür.

length
Verinin uzunluğunu verir.

lower - upper
Küçük - büyük harf dönüşümünü yapar.

random
Listeden rastgele eleman seçer.

time
datetime biçimindeki zamanları göstermek için kullanılır.

urlize
Bir metindeki adresleri url biçiminde ifade eder.

ve daha birçok filtre ve etiket bulunmaktadır. Bunların tamamına https://docs.djangoproject.com/en/dev/ref/templates/builtins/#built-in-filter-reference adresinden ulaşabilirsiniz.

Şimdi de şablon içerisine Python kodunun nasıl yazıldığı ile bir örnek yapalım.İlk olarak views.py dosyamıza aşağıdaki satırı yazarak başlayalım.

from django.template import Template, Context

Şimdi de views.py 'ye görünümümüzü ekleyelim.

def notlar(request):
    ogrenciler =((u'Kadir',u'Guler',40,85,75,True),
                 (u'Ahmet',u'Baba',22,58,36,False),
                 (u'Suzan',u'Keskin',65,75,95,True),
                 (u'Ufuk',u'Hakan',45,15,36,False),
                 (u'Hayrettin',u'Öğüt',50,69,50,True),
                 (u'Mehmet',u'Kaan',42,85,25,True),
                 (u'Ayşe',u'Sanem',35,90,75,True),
            )
    s=Template(u'''<table border="1">
        <tr><th> Sıra </th><th> Adı </th>  <th> Soyadı </th> 
        <th> Vize </th> <th> Ödev </th><th> Final </th><th> Başarı Durumu </th><tr>
        {% for ogr in ogrenciler %}            
            <tr><td>{{forloop.counter}}</td>
            <td>{{ogr.0}}</td>
            <td>{{ogr.1}}</td>
            <td>{{ogr.2}}</td>
            <td>{{ogr.3}}</td>
            <td>{{ogr.4}}</td>
            <td>{% if ogr.5 %} BAŞARILI
                {% else %}     BAŞARISIZ
                {% endif %}
            </td></tr>
        {% endfor %}
        </table>''')

    b = Context({'ogrenciler' : ogrenciler})
    html = s.render(b)
    return HttpResponse(html)

Şimdi de var olan görünüme adres atayalım. Geçen haftalardan hatırlayacağınız üzre bu işlemi urls.py dosyası içerisinde yapıyorduk. urls.py dosyasında urlpatterns değişkenine aşağıdaki satırını ekleyelim:

 url(r'^notlar',views.notlar),

Daha sonra komut satırından Django web sunucusunu çalıştıralım ve tarayıcımızdan
-----------------------------------------------------------------------------------------------------
http://localhost:8000/notlar/
-----------------------------------------------------------------------------------------------------
adresine gidelim. 


















Aslında şablonlar böyle  kullanılmaz ama bizim şu ana kadar yaptıklarımız şablonları daha iyi anlamak içindi. Yani şablonları ayrı bir dosyaya yazmadığımız sürece yazdıklarımız bir anlam taşımamaktadır. O halde şablonu proje klasörümüz içerisine C:\...\deneme\deneme\sablonlar  klasörüne notlar.html diye kaydedelim.

notlar.html

<html>
<head>
    <title> Öğrenci Not Listesi</title>
</head>
<body>
    <table border="1">
        <tr><th> Sıra </th><th> Adı </th>  <th> Soyadı </th> 
        <th> Vize </th> <th> Ödev </th><th> Final </th><th> Başarı Durumu </th><tr>
        {% for ogr in ogrenciler %}            
            <tr><td>{{forloop.counter}}</td>
            <td>{{ogr.0}}</td>
            <td>{{ogr.1}}</td>
            <td>{{ogr.2}}</td>
            <td>{{ogr.3}}</td>
            <td>{{ogr.4}}</td>
            <td>{% if ogr.5 %} BAŞARILI
                {% else %}     BAŞARISIZ
                {% endif %}
            </td></tr>
        {% endfor %}
    </table>
</body>
</html>

Artık gerçek anlamda şablonları kullanmaya başladığımıza göre views.py dosyamızdaki görünümümüzü de değiştirmeliyiz.

views.py
# -*- coding: utf-8 -*-

from django.http import *
from django.template import Template, Context



def notlar(request):
    ogrenciler =((u'Kadir',u'Guler',40,85,75,True),
                 (u'Ahmet',u'Baba',22,58,36,False),
                 (u'Suzan',u'Keskin',65,75,95,True),
                 (u'Ufuk',u'Hakan',45,15,36,False),
                 (u'Hayrettin',u'Öğüt',50,69,50,True),
                 (u'Mehmet',u'Kaan',42,85,25,True),
                 (u'Ayşe',u'Sanem',35,90,75,True),
            )
    s=Template(open('C:...\\deneme\deneme\\sablonlar\\notlar.html').read())

    b = Context({'ogrenciler' : ogrenciler})
    html = s.render(b)
    return HttpResponse(html)

Bundan sonra sayfa görünümündeki değişiklikleri yapmak üzere notlar.html üzerinde çalışabiliriz. Bu şekilde yaptığımızda şablon dosyası yok ise, programımız hata verir. Bundan kurtulmak için Django'nun şablon yükleme sistemini kullanabiliriz. Bunun için öncelikle settings.py dosyasındaki TEMPLATE_DIRS değişkenine projemize ait şablonları kaydedeceğimiz klasörü aşağıdaki gibi eklememiz gerekiyor.

TEMPLATE_DIRS = (
          'C:...\\deneme\deneme\\sablonlar' , 
)

Bunu da yaptıktan sonra views.py dosyamıza son halini verebiliriz demektir. Artık sablonun adresini yazmaktan ziyade sadece adını yazmamız yeterli olacaktır.

views.py
# -*- coding: utf-8 -*-

from django.http import *
from django.template import Template, Context
from django.template.loader import get_template



def notlar(request):
    ogrenciler =((u'Kadir',u'Guler',40,85,75,True),
                 (u'Ahmet',u'Baba',22,58,36,False),
                 (u'Suzan',u'Keskin',65,75,95,True),
                 (u'Ufuk',u'Hakan',45,15,36,False),
                 (u'Hayrettin',u'Öğüt',50,69,50,True),
                 (u'Mehmet',u'Kaan',42,85,25,True),
                 (u'Ayşe',u'Sanem',35,90,75,True),
            )
    s=get_template('notlar.html')

    b = Context({'ogrenciler' : ogrenciler})
    html = s.render(b)
    return HttpResponse(html)

Referanslar :
  1. https://docs.djangoproject.com/en/dev/
  2. BAŞER, Mustafa (2013). Django
  3. http://en.wikipedia.org/wiki/IDLE_(Python)
  4. http://docs.python.org/2/tutorial/index.html