6 Mart 2014 Perşembe

Veritabanı Yapılandırması

Veritabanı yapılandırması için proje içerisinde bulunan settings.py dosyası kullanılır. Bu dosya içerisindeki DATABASE bölümü default olarak şu şekilde gelmektedir.
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
Gördüğünüz gibi veritabanı olarak varsayılan bir biçimde sqlite3 gelmektedir. Varsayılan olarak gelen parametreler dışında kalan parametreleri inceleyelim.
Parametreİşlevi
ENGINEKullanılacak veritabanı sistemi belirtilir.
NAMEVeritabanı ismini içerir.
USERVeritabanı kullanıcısını içerir.
PASSWORDKullanıcı şifresini içerir.
HOSTVeritabanı adresini içerir. Eğer veritabanı yerel makina ile aynı yerde ise boş bırakılır.
PORTVeritabanı standart portunu değil de başka bir portu dinliyorsa PORT numarasını içerir.
Kullanılan veritabanı sistemini ENGINE parametresi ile belirtiyoruz. Veritabanı belirtilmeden önce django.db.backends. takısı ardından veritabanı parametresi yazılır. Kullanılan veri tabanları şu şekildedir:
AyarVeritabanı
django.db.backends.postgresql_psycopg2PostreSQL
django.db.backends.mysqlMYSQL
django.db.backends.sqlite3SQLite
django.db.backends.oracleOracle
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '/veritabani/ornek.db',
  'USER':'mazlum',
  'PASSWORD':'123',
  'HOST':'',
  'PORT':''
    }
}
Veritabanı ismi verilirken veritabanının tam yolu belirtilmelidir.
İlk Model Uygulamamız
Yeni bir örnek çalışma yaparak modelleri bu örnek çalışma üzerinden anlatalım. Küçük bir hastahane otomasyonu yapacağız.
Projemizi oluşturalım.
django-admin.py startproject hastahane
Veritabanı olarak SQLite kullanacağız. Herhangi bir sunucu gereksinimi olmadan çalıştığı için veritabanı sunucu yönetimine gerek kalmadan veritabanı işlemlerimizi halledebileceğiz. Veritabanı dosyası proje dosyamız içerisinde olacağından taşınması gibi durumlarda herhangi bir sorun ile karşılaşmayacağız.
Veritabanı yolunu sistematiksel bir hale getirmek için projemizin ana dizinini bir değişkene atalım. Projemiz içerisindeki settings.py içerisine şu kodları ekliyoruz.
import os.path
dizin = os.path.dirname(__file__)
anadizin = os.path.split(dizin)[0]
DATABASES sözlüğünü kendi projemize göre düzenliyoruz.
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(anadizin, 'db/hastahane.db'),
  'USER': '',
  'PASSWORD':'',
  'HOST':'',
  'PORT':''
    }
}
NAME parametresini veritabanın tam yolunun yazılması gerektiğini unutmamalısınız. Doğrudan yol şeklinde de yazabilirsiniz. Ama projenizin yerini değiştirdiğiniz de NAME parametresini tekrar düzenlemeniz gerekir. Eğer düzenlemezseniz veritabanı bulunamadığı için hata verir. Biz bu problemleri aşabilmek için yolu bulma işin Python'a bıraktık.
Veritabanını projenin ana dizini içerisinde veritabani klasörü içerisinde saklayacağız. Yani veritabanımızın yolu /home/mazlumagar/Django/hastahane/veritabani/hastahane.db şeklinde olacaktır. Projelerdeki karmaşılığın üstesinden gelebilmek için Django'da uygulamalar oluşturulur. Veritabanı işlemlerini yapabilmek için uygulama oluşturacağız. Veritabanı işlemlerini yapabileceğimiz yonetim uygulamasını oluşturalım.
python manage.py startapp yonetim
Bu komut ile projemiz içerisinde şu şekilde bir yapı oluşacaktır.
yonetim/
        __init__.py
        models.py
        tests.py
        views.py
        admin.py
Projemizin uygulamamızı tanıması için eklememiz gerekiyor. hastahane/hastahane/settings.py dosayasına INSTALLED_APPS değişkenine 'yonetim', satırını ekleyeceğiz. Son hali şu şekilde olacak.
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
 'yonetim',
)
Ön tanımlı olarak başka uygulamarında projemize dahil edildiğini görebilirsiniz.
İlk Modelimiz
Daha önce bahsetmiştik. Django ile proje geliştirirken SQL sorguları ile uğraşmayacağız. Ama veritabanı mantığını ve işleyişini bilmemiz gerekiyor. SQL sorgularının Django tarafından otomatik yapılabilmesi için tanımlamalar yapmamız gerekiyor. İşte bu tanımlamalara Model denir. Hastahane projemizin veritabanı sistemi şu şekilde olacak.
hasta_polikilinik tablosunun ilişkilerden oluştuğunu görüyorsunuz. Modelimizi oluşturmak için yonetim/models.py dosyasını açarak ilk Model tanımlamamızı yapıyoruz.
from django.db import models


class Doktor(models.Model):
 adi = models.CharField(max_length=50)
 soyadi = models.CharField(max_length=50)
 telefon = models.CharField(max_length=50,blank=True)
 eposta = models.EmailField(blank=True)

class Polikilinik(models.Model):
 kodu = models.CharField(max_length=20)
 adi = models.CharField(max_length=50)
 doktor = models.ForeignKey(Doktor)

class Hasta(models.Model):
 adi = models.CharField(max_length=50)
 soyadi = models.CharField(max_length=50)
 hasta_polikilinik = models.ManyToManyField(Polikilinik)
Alan türlerini konunun en sonunda tablo şeklinde vereceğiz. Bir alanın boş bırakılabilir olması için blank=True değerini argüman olarak göndermemiz gerekiyor. Doktor tablosunda adı ve soyadı bölümü doldurulmak zorunda iken telefon ve eposta bölümleri boş bırakılabilir. Doktor modeli için Django şu SQL sorgusunu oluşturur.
CREATE TABLE "Doktor" (
 "id" integer NOT NULL PRIMARY KEY,
 "adi" varchar(50) NOT NULL,
 "soyadi" varchar(50) NOT NULL,
 "telefon" varchar(10),
 "eposta" varchar(75)
)
Bu sorgu SQLite içindir. Dikkat ettiyseniz id sütünü biz belirtmemize rağmen otomatik olarak oluştu. Django tablo oluştururken PRIMARY KEY(benzersiz) alanı kendisi oluşturur.
Tablolarımızın yapısını resim olarak gösterirken hasta_polikilinik adında bir tablomuz vardı. Biz model oluştururken o tabloya ait modeli oluşturmadık. Bu oluşturma işini Hasta modelindeki
hasta_polikilinik = models.ManyToManyField(Polikilinik)
satırı ile Django otomatik olarak yapar. Modellerimiz oluşturduğumuza göre herhangi bir hata var mı kontrol edelim.
python manage.py validate
Eğer çıktı 0 errors found şeklinde ise herhangi bir sorun yok demektir. Oluşturduğumuz modellere göre Django'nun oluşturacağı SQL sorgularını görebiliriz.
python manage.py sqlall yonetim
Bu komut ile tüm sorguları istediğimiz bir zamanda -tablolar oluşturulmuş olsa bile- görebiliriz.
BEGIN;
CREATE TABLE "yonetim_doktor" (
    "id" integer NOT NULL PRIMARY KEY,
    "adi" varchar(50) NOT NULL,
    "soyadi" varchar(50) NOT NULL,
    "telefon" varchar(50) NOT NULL,
    "eposta" varchar(75) NOT NULL
)
;
CREATE TABLE "yonetim_polikilinik" (
    "id" integer NOT NULL PRIMARY KEY,
    "kodu" varchar(20) NOT NULL,
    "adi" varchar(50) NOT NULL,
    "doktor_id" integer NOT NULL REFERENCES "yonetim_doktor" ("id")
)
;
CREATE TABLE "yonetim_hasta_hasta_polikilinik" (
    "id" integer NOT NULL PRIMARY KEY,
    "hasta_id" integer NOT NULL,
    "polikilinik_id" integer NOT NULL REFERENCES "yonetim_polikilinik" ("id"),
    UNIQUE ("hasta_id", "polikilinik_id")
)
;
CREATE TABLE "yonetim_hasta" (
    "id" integer NOT NULL PRIMARY KEY,
    "adi" varchar(50) NOT NULL,
    "soyadi" varchar(50) NOT NULL
)
;
CREATE INDEX "yonetim_polikilinik_72173312" ON "yonetim_polikilinik" ("doktor_id");
CREATE INDEX "yonetim_hasta_hasta_polikilinik_3ecb73da" ON "yonetim_hasta_hasta_polikilinik" ("hasta_id");
CREATE INDEX "yonetim_hasta_hasta_polikilinik_12325d4a" ON "yonetim_hasta_hasta_polikilinik" ("polikilinik_id");

COMMIT;
Herhangi bir sorun olmadığına göre ve sorgularımızı da gördüğümüze göre artık tablolarımızı oluşturabiliriz.
python manage.py syncdb
Creating tables ...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table yonetim_doktor
Creating table yonetim_polikilinik
Creating table yonetim_hasta_hasta_polikilinik
Creating table yonetim_hasta
Tablolarımız oluşturduk.
NOT:Django bir model için bir tabloyu bir kere oluşturur. Yani model de yaptığımız değişiklik veritabanına yansımaz. Modeller tasarlanırken dikkatli olunmalı ve eksiksiz olmasını sağlamaya çalışmalıyız. Tablolardaki alanları değiştirme işini kendimiz elle yapmak zorundayız. Veri ekleme,silme ve güncelleme gibi sorgu işlemleri yapmak için Django kobuğunu açıyoruz.
python manage.py shell
Veri Ekleme
>>> from yonetim.models import *
>>> doktor1 =  Doktor(adi='Ahmet',soyadi='Mehmet',telefon='1111',eposta='doktor@mail.com')
>>> doktor1.save()
İlk doktoru tabloya eklemiş olduk. doktor1.save() satırını dikkat edin. Eğer bu şekilde kaydetme işlemini yapmaz isek alan tanımlaması yapılır fakat tabloya eklenmez. doktor1 yazdırarak bildi edinebiliriz.
doktor1
[<Doktor: Ahmet , Mehmet ,doktor@mail.com>]
Daha detaylı bilgilendirme yapmak için. Model içerisinde __unicode__() işlevini tanımlamalıyız. Modelin yeni hali şu şekilde olacaktır.
class Doktor(models.Model):
 adi = models.CharField(max_length=50)
 soyadi = models.CharField(max_length=50)
 telefon = models.CharField(max_length=50,blank=True)
 eposta = models.EmailField(blank=True)

 def __unicode__(self):
  return u'%s , %s ,%s' % (self.adi,self.soyadi,self.eposta)
Değişikliğin etkin olabilmesi için kabuğu yeniden başlatmalısınız. doktor1'i tekrar yazdıralım.
>>> doktor1
[<doktor: ahmet="" doktor="" mail.com="" mehmet="">]
Bir tablodaki tüm verileri alabilmek için objects.all() özelliği kullanılır. İlk önce bir kaç doktor daha ekleyelim.
>>> doktor2 = Doktor(adi='Ali',soyadi='Yılmaz')
>>> doktor2.save()
>>> doktor3 = Doktor(adi='Veysel',soyadi='Duran',eposta='veysel@mail.com'
>>> doktor3.save()
Şimdi Doktor tablosundan tüm verileri çekelim.
>>> doktorlar = Doktor.objects.all()
>>> doktorlar
[<Doktor: Ahmet , Mehmet ,doktor@mail.com>, <Doktor: Ali , Yılmaz ,>, <Doktor: Veysel , Duran ,veysel@mail.com>]
Eğer istersek aldığımız tüm verilerin istediğimiz elemanına şu şekilde ulaşabiliriz.
>>> doktor1 = doktorlar[0]
>>> doktor1.adi
u'Ahmet'
Tüm modellerimize __unicode__() işlevini ekledik. models.py dosyamızın son hali şu şekilde olacak.
from django.db import models

class Doktor(models.Model):
 adi = models.CharField(max_length=50)
 soyadi = models.CharField(max_length=50)
 telefon = models.CharField(max_length=50,blank=True)
 eposta = models.EmailField(blank=True)

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

class Polikilinik(models.Model):
 kodu = models.CharField(max_length=20)
 adi = models.CharField(max_length=50)
 doktor = models.ForeignKey(Doktor)


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

class Hasta(models.Model):
 adi = models.CharField(max_length=50)
 soyadi = models.CharField(max_length=50)
 hasta_polikilinik = models.ManyToManyField(Polikilinik)


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

Şimdi bir polikilinik ekleyelim.
pol1 = Polikilinik(kodu='P404',adi='Serdivan')
Polikilinik içerisindeki doktor alanı verilerini Doktor tablosundan çekiyor. Yani bir ilişki söz konusu olduğu için isim adi alanı gibi bir ekleme yapamazsınız. Deneyelim ve neler olacak bakalım.
pol = Polikilinik(kodu='P405',adi='Adapazari',doktor='Nazlı')
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/base.py", line 405, in __init__
    setattr(self, field.name, rel_obj)
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/fields/related.py", line 327, in __set__
    self.field.name, self.field.rel.to._meta.object_name))
ValueError: Cannot assign "'Nazl\xc4\xb1'": "Polikilinik.doktor" must be a "Doktor" instance.
Gördüğünüz gibi Django bize doktor alanının Doktor tablosundan çekilmesi gerektiğini söylüyor.
Şimdi eklediğimiz ilk polikiliniğin doktorunu Doktor tablosundaki ilk doktor yapalım.
>>> pol1.doktor = doktorlar[0]
>>> pol1.save()
Bu şekilde daha anlaşılır olsun diye yolu uzattık. Daha kısa yoldan şu şekilde yapabilirsiniz.
>>> pol2 = Polikilinik(kodu='P405',adi='Adapazarı',doktor = doktorlar[1])
>>> pol2.save()
Şimdi bir kaç hasta ekleyelim ve bu polikilinikleri o hastaya ekleyelim.
>>> hasta1 = Hasta(adi='Mazlum',soyadi='Agar')
>>> hasta1.save()
>>> hasta2 = Hasta(adi='Yılmaz',soyadi='Gün')
>>> hasta2.save()
hasta1'e polikilinik ekleyelim.
>>> polikilinikler = Polikilinik.objects.all()
>>> hasta1.hasta_polikilinik.add(polikilinikler[0])
>>  hasta1.hasta_polikilinik.add(polikilinikler[1])
Hastaya polikilinik eklemiş olduk. Şimdi bunları görelim.
>>> hasta1.hasta_polikilinik.all()
[<Polikilinik: P404 , Serdivan >, <Polikilinik: P405 , Adapazarı >]
Gördüğünüz eklediğimiz polikilinikler hastada mevcut. İstersek silebiliriz.
>>> hasta1.hasta_polikilinik.remove(polikilinikler[1])
>>> hasta1.hasta_polikilinik.all()
[<Polikilinik: P404 , Serdivan >]
Veri Sorgulama
Önceki bölümde bir Tabloya ait tüm verileri çekmenin objects.all() özelliği ile yaptığımızı gördük. Şimdi filtreleme yaparak istediğimiz alanları çekelim. Bunun için objects.filter() özelliğini kullanacağız.
>>> doktor = Doktor.objects.filter(adi='Ali')
>>> doktor
[<Doktor: Ali , Yılmaz ,<]

Django bizim için şu sorguyu çalıştıracak.
Select * from Doktor where adi='Ali'
Birden fazla koşula bağlayabiliriz.
>>> doktor = Doktor.objects.filter(adi='Ali',soyadi='Yılmaz')
Sorugumuza bakalım.
Select * from Doktor where adi='Ali' and soyadi='Yılmaz'
Adından a harfi geçen doktorları bulmak için __contains özelliğini kullanacağız.
>>> doktor = Doktor.objects.filter(adi__contains='a')
>>> doktor
[<Doktor: Ahmet , Mehmet ,doktor@mail.com>, <Doktor: Ali , Yılmaz ,>]
Veri Sıralama
Sıralama işlemini obects.order_by() özelliği ile yapabiliriz.
>>> Doktor.objects.order_by('adi')
[<Doktor: Ahmet , Mehmet ,doktor@mail.com>, <Doktor: Mahmut , Yılmaz ,>, <Doktor: Veysel , Duran ,veysel@mail.com>]
Doktor tablosunu isme göre sıralamış olduk. Sorgu ise şu şekilde olacaktır.
SELECT *
FROM Doktor
ORDER BY adi;
Eğer ters sıralama yapmak istersek yapmamız gereken tek şey ismin önüne-(eksi) işareti koymak.
>>> Doktor.objects.order_by('-adi')
[<Doktor: Veysel , Duran ,veysel@mail.com>, <Doktor: Mahmut , Yılmaz ,>, <Doktor: Ahmet , Mehmet ,doktor@mail.com>]
Eğer bir tablodan veri çekerken varsayılan olarak bir alana göre sıralanmasını istersek o tabloya ait Modele şu satırları eklememiz gerekir.
class Meta:
    ordering = ['adi']
Modelin son hali şu şekilde olacaktır.
class Polikilinik(models.Model):
 kodu = models.CharField(max_length=20)
 adi = models.CharField(max_length=50)
 doktor = models.ForeignKey(Doktor)


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

 class Meta:
  ordering = ['adi']
Şimdi sıralama özelliğini kullanmadan tablodan tüm verileri çekelim.
>>> polikilinikler = Polikilinik.objects.all()
>>> polikilinikler
[<Polikilinik: P405 , Adapazarı >, <Polikilinik: P404 , Serdivan >]
Polikilinikler sıralı bir biçimde geldi.
Veri Güncelleme
İlk önce veriyi alıp sonra istediğimiz alanı değiştirebiliriz.
>>> doktor = Doktor.objects.filter(adi='Ali')[0]
>>> doktor.adi = 'Mahmut'
>>> doktor.save()
>>> doktor
<Doktor: Mahmut , Yılmaz ,>
Şu şekilde bir kullanımda yapabiliriz
>>> doktor = Doktor.objects.filter(adi='Mahmut').update(eposta='mahmut@mail.com')
>>> doktor
1
Gördüğünüz gibi bu kullanımda eğer güncelleme başarılı ise geriye 1 başarısız size 0 döner. Güncellemeyi kontrol edelim.
>>> doktor = Doktor.objects.filter(adi='Mahmut')
>>> doktor
[<Doktor: Mahmut , Yılmaz ,mahmut@mail.com>]
Sorgusu şu şekilde olacaktır.
UPDATE Doktor
SET eposta = 'mahmut@mail.com'
WHERE adi='Mahmut'
Veri Dilimleme
Veri güncelleme işlemi yaparken aynı zamanda dilimle işlemi de yapmış olduk. Tablodan veri çekerken birden fazla satır gelebilir. Biz istersek bu gelen satırlardan ilkini ikincisini veya birden ona kadar olan aralığını alabiliriz. İlk satırı alalım.
>>> doktor = Doktor.objects.all()[0]
>>> doktor
<Doktor: Ahmet , Mehmet ,doktor@mail.com<
İkinci satırı alalım.
>>> doktor = Doktor.objects.all()[1]
>>> doktor
<Doktor: Mahmut , Yılmaz ,>
İlk on satırı alalım.
>>> doktor = Doktor.objects.all()[0:10]
Doktor tablosundaki ilk 10 satırı geriye döndürecektir. Sorgusu ise şu şekildedir.
SELECT *
FROM Doktor
OFFSET 0 LIMIT 2;
Doktorlar tablosundan ada göre sıralama yaparak ilk satırı getirebiliriz.
>>> doktor = Doktor.objects.order_by('adi')[0]
>>> doktor
<Doktor: Ahmet , Mehmet ,doktor@mail.com>
Verileri dilimlerken negatif sayılar kullanılmaz.
>>> doktor = Doktor.objects.all()[-1]
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/local/lib/python2.7/dist-packages/django/db/models/query.py", line 112, in __getitem__
    "Negative indexing is not supported."
AssertionError: Negative indexing is not supported.
Veri Silme
Nesneleri silmek için delete() metodunu kullanacağız.
>>> doktor_sil = Doktor.objects.filter(adi='Mahmut').delete()
>>> doktorlar = Doktor.objects.all()
>>> doktorlar
[<Doktor: Ahmet , Mehmet ,doktor@mail.com>, <Doktor: Veysel , Duran ,veysel@mail.com>]
Mahmut isimli kullanıcıyı sildik. Doktor tablosundaki tüm satırları silebiliriz.
Doktor.objects.all().delete()
Silme işlemini şu şekilde de yapabiliriz.
>>> doktor_sil = Doktor.objects.get(adi='Veysel')
>>> doktor_sil.delete()
>>> doktorlar
[<Doktor: Ahmet , Mehmet ,doktor@mail.com>]
Veysel isimli dokturu da silmiş olduk.
Diğer model alan tiplerine buradan ulaşabilirsiniz.
Kaynakça

1 yorum :

  1. Merhabalar, yazınız için çok teşekkür ederim öncelikle fakat bi sorum olacaktı ;

    ör;
    class x(models.Model):
    ad = models.CharField(max_length=50,blank=False)

    class y(models.Model):
    adres = models.CharField(max_length=100,blank=False)
    xx = models.ForeignKey(x)

    gibi bir modelimiz var. Burada xx foregin keyini otomatik olarak atayamıyormuyuz ??
    xx = models.ForeignKey(x , otomatikOluştur = x.pk) gibi . Birşey yok mu ?

    YanıtlayınSil