Jumping Into Django Models: Veri Modellemenin Kalbine Bir Dalış
Django, hızlı ve verimli web uygulamaları geliştirmek için tasarlanmış, yüksek seviyeli bir Python web çatısıdır. “Batteries included” felsefesiyle, geliştiricilerin veritabanı etkileşiminden URL yönlendirmesine, kullanıcı kimlik doğrulamasından yönetim paneline kadar birçok temel ihtiyacını karşılayacak araçlar sunar. Bu araçların merkezinde, uygulamanızın verilerini tanımlamanızı ve onlarla etkileşim kurmanızı sağlayan Django Modelleri yer alır. Django Modelleri, bir web uygulamasının “MVT” (Model-View-Template) mimarisindeki “M” harfini temsil eder ve uygulamanızın veri katmanını oluşturur.
Bu makalede, Django Modellerinin derinliklerine inecek, ne olduklarını, neden bu kadar güçlü olduklarını ve gerçek dünya senaryolarında nasıl kullanıldıklarını adım adım keşfedeceğiz. Temel model tanımlamalarından karmaşık ilişkilere, güçlü sorgu setlerinden özel model metotlarına kadar geniş bir yelpazeyi ele alarak, Django Modelleri ile çalışmaya başlamanız için sağlam bir temel oluşturacağız.
Temel Kavramlar ve Avantajları
Django Modelleri, uygulamanızın veritabanı şemasını tanımlayan Python sınıflarıdır. Her model sınıfı, veritabanındaki bir tabloyu temsil eder ve bu sınıfın her bir niteliği (attribute) ise o tablonun bir sütununa karşılık gelir. Bu soyutlama katmanı, geliştiricilerin SQL sorguları yazmak zorunda kalmadan Python kodları aracılığıyla veritabanı ile etkileşim kurmasını sağlar.
ORM (Object-Relational Mapping) Nedir?
Django Modellerinin temelinde, bir ORM (Object-Relational Mapping) aracı yatar. ORM, nesne yönelimli programlama dillerindeki (bu durumda Python) sınıfları ve nesneleri, ilişkisel veritabanlarındaki tablolar ve satırlarla eşleştiren bir tekniktir. Django’nun ORM’si sayesinde:
* Veritabanı Bağımsızlığı: Uygulamanızı PostgreSQL, MySQL, SQLite veya Oracle gibi farklı veritabanı sistemlerinde, kodunuzda büyük değişiklikler yapmadan çalıştırabilirsiniz. ORM, Python objelerini veritabanına özgü SQL ifadelerine çevirme işini üstlenir.
* Daha Az SQL Kodu: Veritabanı işlemlerini (oluşturma, okuma, güncelleme, silme – CRUD) doğrudan Python objeleri ve metotları aracılığıyla yaparsınız. Bu, geliştirme sürecini hızlandırır ve SQL enjeksiyonu gibi yaygın güvenlik açıklarının önüne geçer.
* Daha Okunabilir ve Bakımı Kolay Kod: Veritabanı şemanız, açıkça tanımlanmış Python sınıfları olarak temsil edildiğinden, kodunuz daha anlaşılır ve bakımı daha kolay hale gelir.
* Pythonic Yaklaşım: Verilerinizle tıpkı normal Python objeleriyle çalışır gibi etkileşim kurarsınız.
Model Tanımlamanın Temelleri
Bir Django modeli tanımlamak oldukça basittir. Genellikle, her Django uygulaması için models.py adında bir dosya bulunur ve modeller bu dosyanın içine yazılır. Tüm modeller django.db.models.Model sınıfından miras almalıdır.
İşte basit bir Kitap modelinin tanımı:
from django.db import models
class Kitap(models.Model):
baslik = models.CharField(max_length=200)
yazar = models.CharField(max_length=100)
yayin_tarihi = models.DateField()
isbn = models.CharField(max_length=13, unique=True)
sayfa_sayisi = models.IntegerField(null=True, blank=True)
fiyat = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
stok_durumu = models.BooleanField(default=True)
def __str__(self):
return self.baslik
Bu örnekte:
* Kitap sınıfı, veritabanında myapp_kitap (varsayılan olarak uygulama adı ve model adının küçük harfle birleşimi) adında bir tabloya karşılık gelir.
* baslik, yazar, yayin_tarihi gibi nitelikler, bu tablonun sütunlarıdır.
* Her nitelik, veritabanında saklanacak verinin türünü belirten bir Field objesidir (örn. CharField, DateField).
* max_length, unique, null, blank, default gibi argümanlar, alanın davranışını ve veritabanı kısıtlamalarını tanımlar.
Modellerinizi tanımladıktan sonra, Django’nun bu modelleri veritabanı şemasına dönüştürmesi için iki komutu çalıştırmanız gerekir:
1. python manage.py makemigrations: Modellerinizdeki değişiklikleri algılar ve bu değişiklikleri uygulayacak bir geçiş (migration) dosyası oluşturur.
2. python manage.py migrate: Oluşturulan geçiş dosyalarını veritabanına uygular, yani tabloları ve sütunları oluşturur veya günceller.
Bu adımlar, geliştirme sürecinizde veritabanı şemanızı model tanımlarınızla senkronize tutmanın anahtarıdır.
Model Alan Türleri (Field Types)
Django, çok çeşitli veri türlerini desteklemek için zengin bir alan türleri koleksiyonu sunar. Her alan türü, veritabanında belirli bir veri tipine eşlenir ve Python tarafında uygun veri türlerini işler.
Sık Kullanılan Alan Türleri
* models.CharField(max_length=...): Kısa metin dizileri için kullanılır. max_length zorunlu bir argümandır ve veritabanında bu alanın alabileceği maksimum karakter sayısını belirtir.
* models.TextField(): Uzun metinler için kullanılır. CharField‘dan farklı olarak max_length argümanı zorunlu değildir ve genellikle metin alanları için daha büyük boyutlara izin verir.
* models.IntegerField(): Tam sayılar için.
* models.PositiveIntegerField(): Pozitif tam sayılar (sıfır dahil) için.
* models.SmallIntegerField(): Küçük tam sayılar için.
* models.BooleanField(default=False): True/False değerleri için. Genellikle bir varsayılan değer (default) ile kullanılır.
* models.DateField(): Tarih değerleri için (örn. YYYY-MM-DD).
* auto_now_add=True: Obje ilk oluşturulduğunda otomatik olarak mevcut tarihi ayarlar. Yalnızca oluşturma anında bir kez ayarlanır.
* auto_now=True: Obje her kaydedildiğinde otomatik olarak mevcut tarihi günceller.
* models.DateTimeField(): Tarih ve saat değerleri için (örn. YYYY-MM-DD HH:MM:SS). auto_now_add ve auto_now argümanları burada da geçerlidir.
* models.DecimalField(max_digits=..., decimal_places=...): Ondalıklı sayılar için.
* max_digits: Sayıdaki toplam basamak sayısı (ondalık basamaklar dahil).
* decimal_places: Ondalık noktasından sonraki basamak sayısı.
* models.EmailField(max_length=...): E-posta adresleri için özel doğrulama sağlar. CharField‘dan miras alır.
* models.URLField(max_length=...): URL’ler için özel doğrulama sağlar. CharField‘dan miras alır.
* models.FileField(upload_to=...): Dosya yüklemek için kullanılır. upload_to argümanı, dosyaların sunucuda hangi dizine yükleneceğini belirtir.
* models.ImageField(upload_to=...): Resim dosyaları için kullanılır. FileField‘dan miras alır ve ek olarak resim doğrulama özellikleri sunar.
Alan Seçenekleri (Field Options)
Her alan türü, davranışını daha da özelleştirmek için bir dizi ortak argümanı kabul eder:
* null=True: Veritabanında bu alanın NULL değerini almasına izin verir. Varsayılan olarak False‘tur.
* blank=True: Django yönetim paneli ve formlarında bu alanın boş bırakılmasına izin verir. null ile karıştırılmamalıdır; blank doğrulama ile ilgilidir, null veritabanı ile. Varsayılan olarak False‘tur.
* default=...: Alan boş bırakıldığında kullanılacak varsayılan değeri ayarlar.
* unique=True: Veritabanında bu alanın değerlerinin benzersiz olmasını sağlar.
* primary_key=True: Bu alanı modelin birincil anahtarı yapar. Django her modele otomatik olarak id adında bir AutoField birincil anahtar eklediği için genellikle manuel olarak ayarlamanıza gerek kalmaz.
* verbose_name="Okunabilir İsim": Yönetici paneli ve formlarda alanın daha kullanıcı dostu bir adla görüntülenmesini sağlar. Belirtilmezse, alan adının ilk harfi büyük yapılır ve alt çizgiler boşluklarla değiştirilir.
* help_text="Bu alan hakkında yardım metni": Yönetici paneli ve formlarda alanın yanında küçük bir yardım metni görüntüler.
* choices=[('value1', 'Display Name 1'), ('value2', 'Display Name 2')]: Bir dizi seçenek sunar. Veritabanına value kaydedilirken, formlarda Display Name gösterilir.
class Urun(models.Model):
ADET_BIRIMLERI = [
('ADET', 'Adet'),
('KG', 'Kilogram'),
('LT', 'Litre'),
]
ad = models.CharField(max_length=100, verbose_name="Ürün Adı")
fiyat = models.DecimalField(max_digits=10, decimal_places=2)
stok = models.IntegerField(default=0)
birim = models.CharField(max_length=4, choices=ADET_BIRIMLERI, default='ADET')
aciklama = models.TextField(blank=True, null=True, help_text="Ürünün detaylı açıklaması")
eklenme_tarihi = models.DateTimeField(auto_now_add=True)
guncellenme_tarihi = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['ad']
verbose_name = "Ürün"
verbose_name_plural = "Ürünler"
def __str__(self):
return self.ad
Bu örnekte, birim alanı için choices kullanılarak sadece belirli değerlerin seçilebilmesi sağlanmıştır. Ayrıca verbose_name, help_text, auto_now_add ve auto_now gibi seçeneklerin kullanımı da gösterilmiştir.
İlişkiler (Relationships)
Gerçek dünya uygulamalarında veriler genellikle birbirine bağlıdır. Django Modelleri, ilişkisel veritabanlarındaki tablo ilişkilerini (bire-bir, bire-çok, çoka-çok) kolayca tanımlamanıza olanak tanır.
Bir-Çok İlişkisi (ForeignKey)
En yaygın ilişki türüdür. Bir modelin birçok örneğinin başka bir modelin tek bir örneğine bağlı olduğu durumu ifade eder. Örneğin, bir yazarın birden fazla kitabı olabilir, ancak her kitap yalnızca bir yazara aittir.
class Yazar(models.Model):
ad = models.CharField(max_length=100)
soyad = models.CharField(max_length=100)
dogum_tarihi = models.DateField(null=True, blank=True)
def __str__(self):
return f"{self.ad} {self.soyad}"
class Kitap(models.Model):
baslik = models.CharField(max_length=200)
# ForeignKey ile Yazar modeline bağlanıyoruz
yazar = models.ForeignKey(Yazar, on_delete=models.CASCADE)
yayin_tarihi = models.DateField()
def __str__(self):
return self.baslik
models.ForeignKey alanını tanımlarken, ilk argüman olarak ilişkili modelin adını (veya string olarak ‘UygulamaAdı.ModelAdı’) verirsiniz. İkinci zorunlu argüman on_delete, ilişkili obje silindiğinde ne olacağını belirtir:
* models.CASCADE: İlişkili obje silindiğinde, bu objeyi de sil. (En yaygın ve varsayılan davranış)
* models.PROTECT: İlişkili objeler varsa bu objenin silinmesini engelle.
* models.SET_NULL: İlişkili obje silindiğinde bu alanı NULL olarak ayarla. (null=True ile birlikte kullanılmalıdır.)
* models.SET_DEFAULT: İlişkili obje silindiğinde bu alanı varsayılan değere ayarla. (default ile birlikte kullanılmalıdır.)
* models.DO_NOTHING: İlişkili obje silindiğinde hiçbir şey yapma. (Veritabanı tutarsızlığına yol açabilir, dikkatli kullanılmalı.)
* models.RESTRICT: İlişkili objeler varsa bu objenin silinmesini engelle, ancak PROTECT‘ten farklı olarak veritabanı seviyesinde kısıtlama uygulanır.
related_name argümanı, ilişkili modelden (bu örnekte Yazar‘dan) bu modele (yani Kitap‘a) geri dönüş sorgularını yaparken kullanılacak isimdir. Örneğin, yazar.kitap_set.all() yerine yazar.kitaplar.all() yazmak için:
class Kitap(models.Model):
# ...
yazar = models.ForeignKey(Yazar, on_delete=models.CASCADE, related_name='kitaplar')
# ...
Şimdi yazar_objesi.kitaplar.all() ile o yazarın tüm kitaplarına erişebilirsiniz.
Bir-Bir İlişkisi (OneToOneField)
Bir modelin her örneğinin başka bir modelin yalnızca bir örneğiyle ilişkili olduğu durumu ifade eder. Genellikle bir modelin temel özelliklerini ana modelden ayırmak veya bir kullanıcının profil bilgilerini ayrı bir modelde tutmak gibi senaryolarda kullanılır.
from django.contrib.auth.models import User
class KullaniciProfili(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
telefon = models.CharField(max_length=15, blank=True, null=True)
adres = models.CharField(max_length=255, blank=True, null=True)
profil_resmi = models.ImageField(upload_to='profil_resimleri/', blank=True, null=True)
def __str__(self):
return self.user.username
Burada, her User objesi yalnızca bir KullaniciProfili objesine sahip olabilir ve tersi de geçerlidir. User objesinden user_objesi.kullaniciprofili ile profile erişilebilir.
Çok-Çok İlişkisi (ManyToManyField)
Bir modelin birden çok örneğinin başka bir modelin birden çok örneğiyle ilişkili olduğu durumu ifade eder. Örneğin, bir kitap birden fazla kategoriye ait olabilir ve bir kategori birden fazla kitaba sahip olabilir.
class Kategori(models.Model):
ad = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.ad
class Kitap(models.Model):
baslik = models.CharField(max_length=200)
yazar = models.ForeignKey(Yazar, on_delete=models.CASCADE)
# ManyToManyField ile Kategori modeline bağlanıyoruz
kategoriler = models.ManyToManyField(Kategori)
def __str__(self):
return self.baslik
ManyToManyField kullanıldığında, Django otomatik olarak bu iki model arasında bir ara tablo (intermediate table) oluşturur. Bu tablo, her kitabın hangi kategorilere ait olduğunu ve her kategorinin hangi kitapları içerdiğini tutar. İlişkiye obje eklemek için kitap_objesi.kategoriler.add(kategori_objesi) veya kitap_objesi.kategoriler.set([kategori1, kategori2]) gibi metotlar kullanılır.
Model Yöneticileri (Managers) ve Sorgular (Queries)
Django ORM’nin en güçlü yönlerinden biri, veritabanından veri almak için sunduğu esnek ve Pythonic sorgu API’sidir. Her model, varsayılan olarak objects adında bir Manager‘a sahiptir. Bu Manager objesi, veritabanı sorgularını yürütmek için ana giriş noktasıdır.
Temel Sorgu Yöntemleri
* Tüm objeleri alma: Model.objects.all()
tum_kitaplar = Kitap.objects.all()
* Belirli bir objeyi alma (get): Model.objects.get(pk=1) veya Model.objects.get(baslik='Savaş ve Barış'). Tek bir sonuç beklenir. Birden fazla sonuç veya hiç sonuç yoksa hata fırlatır (MultipleObjectsReturned veya DoesNotExist).
kitap = Kitap.objects.get(id=1)
* Filtreleme (filter): Model.objects.filter(field='value'). Bir QuerySet döndürür (sonuç kümesi).
tolstoy_kitaplari = Kitap.objects.filter(yazar__soyad='Tolstoy')
* Hariç Tutma (exclude): Model.objects.exclude(field='value'). Belirtilen kriterlere uyanları hariç tutar.
diger_kitaplar = Kitap.objects.exclude(yazar__soyad='Tolstoy')
* Yeni obje oluşturma ve kaydetme:
yeni_kitap = Kitap.objects.create(baslik='Yeni Kitap', yazar=yazar_objesi, yayin_tarihi='2023-01-01')
# Veya
yeni_kitap = Kitap(baslik='Yeni Kitap 2', yazar=yazar_objesi, yayin_tarihi='2023-02-01')
yeni_kitap.save() # Obje veritabanına kaydedilir
* Toplu oluşturma: Model.objects.bulk_create([...]). Tek bir veritabanı sorgusuyla birden fazla obje oluşturmak için performanslı bir yöntem.
* Güncelleme: Mevcut bir objeyi alıp niteliklerini değiştirip save() metoduyla kaydedebilirsiniz.
kitap = Kitap.objects.get(id=1)
kitap.fiyat = 29.99
kitap.save()
* Toplu güncelleme: QuerySet üzerinde update() metoduyla birden fazla objeyi tek bir sorguda güncelleyebilirsiniz.
Kitap.objects.filter(yazar__ad='Lev').update(fiyat=35.00)
* Silme: Bir objeyi alıp delete() metoduyla silebilirsiniz.
kitap = Kitap.objects.get(id=1)
kitap.delete()
* Toplu silme: QuerySet üzerinde delete() metoduyla birden fazla objeyi tek bir sorguda silebilirsiniz.
Kitap.objects.filter(yazar__ad='Lev').delete()
QuerySet Metotları
filter() veya all() gibi metotlar bir QuerySet döndürür. QuerySet‘ler zincirleme metot çağrılarına izin verir ve lazy (tembel) bir yapıya sahiptir; yani veritabanı sorgusu, QuerySet üzerinde gerçekten veri istendiğinde (örn. döngüye sokulduğunda, list()‘e dönüştürüldüğünde) yürütülür.
* order_by('alan_adi'): Sonuçları belirli bir alana göre sıralar. - önekiyle tersten sıralanır (örn. order_by('-yayin_tarihi')).
* values('alan1', 'alan2'): QuerySet‘teki her obje için sadece belirtilen alanları içeren sözlükler listesi döndürür.
* values_list('alan1', 'alan2', flat=True): Belirtilen alanların değerlerini içeren tuple’lar listesi döndürür. flat=True ile tek bir alan seçildiğinde tek değerler listesi döndürür.
* count(): QuerySet‘teki obje sayısını döndürür.
* exists(): QuerySet‘te en az bir obje olup olmadığını kontrol eder (True veya False).
* first(), last(): QuerySet‘teki ilk veya son objeyi döndürür (sıralama varsa).
* distinct(): Tekrarlayan satırları kaldırır.
* annotate(): Her objeye yeni bir alan eklemek için kullanılır (örn. toplam, ortalama gibi agregasyonlar).
* aggregate(): QuerySet‘in tamamı üzerinde bir agregasyon işlemi yapar (örn. tüm kitapların ortalama fiyatı).
Filtreleme İfadeleri (Lookups)
filter(), exclude(), get() gibi metotlarda, alan adının sonuna çift alt çizgi (__) ile eklenen ifadelerle karmaşık filtrelemeler yapabilirsiniz:
* exact: Tam eşleşme (varsayılan). field__exact='value'
* iexact: Büyük/küçük harf duyarsız tam eşleşme. field__iexact='value'
* contains: Metin içinde geçiyor mu? field__contains='metin'
* icontains: Büyük/küçük harf duyarsız metin içinde geçiyor mu?
* startswith, istartswith: Belirli bir metinle başlıyor mu?
* endswith, iendswith: Belirli bir metinle bitiyor mu?
* gt, gte: Büyüktür, büyük veya eşittir. field__gt=10
* lt, lte: Küçüktür, küçük veya eşittir. field__lt=10
* in: Bir liste veya tuple içindeki değerlerden biriyle eşleşiyor mu? field__in=['deger1', 'deger2']
* range: Belirli bir aralıkta mı? field__range=(baslangic, bitis)
* isnull: NULL mu? field__isnull=True
* year, month, day, week_day, hour, minute, second: Tarih/saat alanlarının belirli bölümlerine göre filtreleme. tarih_alani__year=2023
İlişkili objeler üzerinden filtreleme de yapabilirsiniz:
# Adı 'Lev' olan yazarın kitaplarını bul
kitaplar = Kitap.objects.filter(yazar__ad='Lev')
Kategorisi 'Roman' olan kitapları bul
romanlar = Kitap.objects.filter(kategoriler__ad='Roman')
Özel Yöneticiler (Custom Managers)
Modelin varsayılan objects yöneticisi genellikle yeterli olsa da, belirli sorguları sık sık kullanıyorsanız veya modelinize özel bir sorgu API’si eklemek istiyorsanız özel bir yönetici oluşturabilirsiniz.
class AktifKitapManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(stok_durumu=True)
def pahali_kitaplar(self):
return self.get_queryset().filter(fiyat__gt=50)
class Kitap(models.Model):
# ... (Yukarıdaki Kitap modeli alanları)
stok_durumu = models.BooleanField(default=True)
objects = models.Manager() # Varsayılan yönetici
aktif_kitaplar = AktifKitapManager() # Özel yönetici
def __str__(self):
return self.baslik
Şimdi, Kitap.aktif_kitaplar.all() ile sadece stokta olan kitapları alabilir veya Kitap.aktif_kitaplar.pahali_kitaplar() ile stokta olan pahalı kitapları sorgulayabilirsiniz.
Model Metotları
Django modelleri sadece veri depolamakla kalmaz, aynı zamanda veriler üzerinde işlemler gerçekleştiren metotlar da içerebilir. Bu metotlar, modelin davranışını özelleştirmenize olanak tanır.
__str__ Metodu
Her modelde __str__ metodunu tanımlamak iyi bir pratiktir. Bu metot, objenin insan tarafından okunabilir bir string temsilini döndürür. Özellikle Django yönetim panelinde ve objeleri konsolda yazdırırken çok kullanışlıdır.
class Kitap(models.Model):
baslik = models.CharField(max_length=200)
# ...
def __str__(self):
return self.baslik # Kitap objesi 'Savaş ve Barış' olarak görünür
save() Metodu
Objeyi veritabanına kaydetmeden önce veya sonra özel bir mantık çalıştırmak isterseniz, save() metodunu geçersiz kılabilirsiniz.
class Urun(models.Model):
ad = models.CharField(max_length=100)
fiyat = models.DecimalField(max_digits=10, decimal_places=2)
indirimli_fiyat = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
def save(self, args, *kwargs):
# Kaydetmeden önce indirimli fiyatı hesapla
if self.fiyat > 100:
self.indirimli_fiyat = self.fiyat * Decimal('0.9') # %10 indirim
else:
self.indirimli_fiyat = self.fiyat
super().save(args, *kwargs) # Üst sınıfın save metodunu çağır
Önemli: super().save(args, *kwargs) metodunu çağırmayı unutmayın, aksi takdirde obje aslında veritabanına kaydedilmeyecektir.
delete() Metodu
Objeyi veritabanından silmeden önce veya sonra özel bir mantık çalıştırmak için delete() metodunu geçersiz kılabilirsiniz.
import os
from django.conf import settings
class ProfilResmi(models.Model):
kullanici = models.OneToOneField(User, on_delete=models.CASCADE)
resim = models.ImageField(upload_to='profil_resimleri/')
def delete(self, args, *kwargs):
# Resmi veritabanından silmeden önce dosya sisteminden de sil
if self.resim:
if os.path.isfile(self.resim.path):
os.remove(self.resim.path)
super().delete(args, *kwargs)
get_absolute_url() Metodu
Bir objenin detay sayfasına yönlendiren URL’yi döndürmek için bu metodu kullanabilirsiniz. Bu, özellikle şablonlarda veya yönetim panelinde objeye bağlantı oluştururken DRY (Don’t Repeat Yourself) prensibini uygulamanızı sağlar.
from django.urls import reverse
class Kitap(models.Model):
# ...
def get_absolute_url(self):
return reverse('kitap_detay', args=[str(self.id)])
Ardından şablonunuzda {{ kitap.get_absolute_url }} şeklinde kullanabilirsiniz.
Meta Sınıfı
Her model sınıfının içinde isteğe bağlı olarak bir class Meta: sınıfı tanımlayabilirsiniz. Bu sınıf, modelin veritabanı dışındaki davranışını ve seçeneklerini belirtmek için kullanılır.
class Meta: İçindeki Seçenekler
* verbose_name = "Tekil İsim": Yönetim panelinde modelin tekil adını belirler.
* verbose_name_plural = "Çoğul İsim": Yönetim panelinde modelin çoğul adını belirler. (Belirtilmezse Django, verbose_name‘e ‘s’ eklemeye çalışır.)
* ordering = ['alan_adi']: Modelden obje sorgulandığında varsayılan sıralamayı belirler. '-alan_adi' ile azalan sıralama yapılır.
* unique_together = [['alan1', 'alan2']]: Belirtilen alanların kombinasyonunun veritabanında benzersiz olmasını sağlar. Örneğin, bir kullanıcının aynı tarihte birden fazla yorum yapmasını engellemek için.
class Yorum(models.Model):
kullanici = models.ForeignKey(User, on_delete=models.CASCADE)
kitap = models.ForeignKey(Kitap, on_delete=models.CASCADE)
yorum_tarihi = models.DateField()
class Meta:
unique_together = [['kullanici', 'kitap', 'yorum_tarihi']]
* db_table = 'ozel_tablo_adi': Modelin veritabanındaki tablo adını manuel olarak belirler. Varsayılan olarak Django, uygulama_adı_model_adı şeklinde bir isim kullanır.
* abstract = True: Bu modeli soyut bir temel sınıf yapar. Kendi veritabanı tablosu olmaz, ancak diğer modeller ondan miras alabilir ve alanlarını kullanabilir.
* app_label = 'baska_uygulama': Modelin ait olduğu uygulamayı belirtir. Genellikle model farklı bir uygulamanın models.py dosyasında tanımlandığında kullanılır.
* indexes = [models.Index(fields=['alan_adi'])]: Veritabanı indeksleri oluşturarak sorgu performansını artırır. Özellikle sıkça sorgulanan alanlar için faydalıdır.
Veritabanı Geçişleri (Migrations)
Django Modelleri, uygulamanızın veritabanı şemasının evrimini yönetmek için güçlü bir geçiş (migrations) sistemi sunar. Bir modelde değişiklik yaptığınızda (yeni alan ekleme, alan türü değiştirme, model silme vb.), bu değişikliklerin veritabanına yansıtılması gerekir.
Neden Geçişler?
* Şema Yönetimi: Modellerinizdeki değişiklikleri veritabanına güvenli bir şekilde uygulamanızı sağlar.
* Versiyon Kontrolü: Geçiş dosyaları kodunuzla birlikte versiyon kontrol sistemlerinde (Git gibi) saklanır, böylece veritabanı şemanızın geçmişini takip edebilirsiniz.
* Geliştirme Ortamı Tutarlılığı: Ekip üyeleri ve farklı ortamlar (geliştirme, test, üretim) arasında veritabanı şemasının tutarlılığını sağlar.
Temel Komutlar
1. python manage.py makemigrations [uygulama_adı]: Modellerinizde yapılan değişiklikleri (yeni model, yeni alan vb.) algılar ve bu değişiklikleri veritabanına uygulamak için bir Python dosyası (geçiş dosyası) oluşturur. Uygulama adı belirtilmezse tüm uygulamalardaki değişiklikleri kontrol eder.
python manage.py makemigrations myapp
Bu komut, myapp/migrations/ dizininde 0001_initial.py, 0002_add_new_field.py gibi dosyalar oluşturacaktır.
2. python manage.py migrate [uygulama_adı] [geçiş_adı]: Oluşturulan geçiş dosyalarını veritabanına uygular. Bu, veritabanı tablolarını oluşturur, sütunları ekler/değiştirir veya siler. Geçiş adı belirtilmezse, o uygulamadaki tüm bekleyen geçişleri uygular.
python manage.py migrate myapp
Bu komutu çalıştırdığınızda, Django geçiş dosyalarını sırayla okur ve her birindeki veritabanı işlemlerini gerçekleştirir.
3. python manage.py showmigrations [uygulama_adı]: Uygulamalarınızdaki geçişlerin listesini ve her birinin uygulanıp uygulanmadığını gösterir.
python manage.py showmigrations
4. python manage.py sqlmigrate : Belirli bir geçiş dosyası için çalıştırılacak ham SQL komutlarını gösterir. Bu, geçişin veritabanı üzerinde ne gibi bir etki yaratacağını anlamak için faydalıdır.
python manage.py sqlmigrate myapp 0001_initial
Geçişler, Django geliştirme iş akışının vazgeçilmez bir parçasıdır ve model değişikliklerini yönetmek için güvenilir bir mekanizma sunar.
Gelişmiş Konulara Kısa Bakış
Django Modelleri, temel CRUD işlemlerinin ve ilişkilerin ötesinde, daha karmaşık senaryoları ele almak için çeşitli gelişmiş özellikler sunar.
Proxy Modeller
Proxy modeller, mevcut bir modelin veritabanı şemasını değiştirmeden ona yeni davranışlar (metotlar, yöneticiler) eklemenizi sağlar. Temel modelle aynı veritabanı tablosunu kullanır, sadece Python seviyesinde farklı bir arayüz sunar.
class Siparis(models.Model):
durum = models.CharField(max_length=20, default='beklemede')
# ...
class AktifSiparis(Siparis):
class Meta:
proxy = True
ordering = ['-id']
def iptal_et(self):
self.durum = 'iptal edildi'
self.save()
Şimdi AktifSiparis.objects.all() çağrısı Siparis tablosundan veri alır,
ancak iptal_et metodu sadece AktifSiparis objelerinde mevcuttur.
Çoklu Tablo Kalıtımı (Multi-table Inheritance)
Python’daki normal kalıtım gibi çalışır, ancak her model kendi veritabanı tablosuna sahiptir. Alt model, üst modelin birincil anahtarına bir OneToOneField ile bağlanır. Bu, verileri farklı tablolara bölmek ve ortak alanları üst sınıfta tanımlamak için kullanışlıdır.
class TemelUrun(models.Model):
ad = models.CharField(max_length=100)
fiyat = models.DecimalField(max_digits=10, decimal_places=2)
class KitapUrun(TemelUrun):
isbn = models.CharField(max_length=13)
yazar = models.CharField(max_length=100)
class ElektronikUrun(TemelUrun):
marka = models.CharField(max_length=50)
garanti_suresi = models.IntegerField()
Bu durumda, KitapUrun ve ElektronikUrun modelleri TemelUrun‘den miras alır ve her biri kendi özel alanlarına sahip ayrı birer tablo olarak veritabanında yer alır. TemelUrun‘ün alanları da kendi tablosunda bulunur ve alt modeller bu tabloya birincil anahtar aracılığıyla bağlıdır.
Soyut Temel Sınıflar (Abstract Base Classes)
Çoklu tablo kalıtımının aksine, soyut temel sınıflar kendi başlarına bir veritabanı tablosu oluşturmazlar. Bunun yerine, ortak alanları ve metotları tanımlamak ve diğer modellere miras vermek için kullanılırlar. Miras alan her model, soyut temel sınıftaki alanları kendi veritabanı tablosunda oluşturur.
class ZamanDamgaliModel(models.Model):
olusturma_tarihi = models.DateTimeField(auto_now_add=True)
guncelleme_tarihi = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
ordering = ['-olusturma_tarihi']
class Yazi(ZamanDamgaliModel):
baslik = models.CharField(max_length=200)
icerik = models.TextField()
class Yorum(ZamanDamgaliModel):
yazi = models.ForeignKey(Yazi, on_delete=models.CASCADE)
metin = models.TextField()
ZamanDamgaliModel soyut olduğu için kendi tablosu yoktur. Ancak Yazi ve Yorum modelleri, olusturma_tarihi ve guncelleme_tarihi alanlarına sahip olacaktır.
Raw SQL ve Veritabanı Fonksiyonları
Nadiren de olsa, Django ORM’nin sunduğu araçların yetersiz kaldığı durumlar olabilir. Bu durumlarda, ham SQL sorguları yazabilir veya Django’nun F() ve Q() objeleri gibi daha gelişmiş ORM özelliklerini kullanabilirsiniz.
* F() objeleri: Bir modelin alanları arasındaki değerleri doğrudan veritabanı seviyesinde karşılaştırmak veya güncellemek için kullanılır. Bu, veritabanından veri çekip Python’da işlem yapıp geri kaydetmek yerine, tek bir veritabanı sorgusuyla işlemi halletmenizi sağlar.
from django.db.models import F
# Tüm ürünlerin fiyatını %10 artır
Urun.objects.update(fiyat=F('fiyat') * 1.1)
* Q() objeleri: Karmaşık AND ve OR koşullarıyla sorgular oluşturmak için kullanılır.
from django.db.models import Q
# Yazar adı 'Lev' VEYA soyadı 'Tolstoy' olan kitapları bul
kitaplar = Kitap.objects.filter(Q(yazar__ad='Lev') | Q(yazar__soyad='Tolstoy'))
# Yazar adı 'Lev' VE yayım tarihi 2000'den büyük olan kitapları bul
kitaplar = Kitap.objects.filter(Q(yazar__ad='Lev') & Q(yayin_tarihi__year__gt=2000))
* raw() metodu: Ham SQL sorguları çalıştırmak ve sonuçları model objeleri olarak almak için kullanılır.
for p in Kitap.objects.raw('SELECT * FROM myapp_kitap WHERE yazar_id = %s', [1]):
print(p.baslik)
* django.db.connection.cursor(): Tamamen ham SQL sorguları çalıştırmak ve sonuçları doğrudan veritabanı imlecinden almak için kullanılır. Bu, en düşük seviyeli yaklaşımdır ve genellikle özel raporlama veya performans kritik işlemler için tercih edilir.
Sonuç
Django Modelleri, Django çatısının kalbinde yer alır ve web uygulamalarınızın veri katmanını oluşturur. ORM’nin sağladığı soyutlama sayesinde, veritabanı işlemleri Pythonic bir şekilde yürütülür, geliştirme süreci hızlanır ve kodun bakımı kolaylaşır. Bu makalede, temel model tanımlamalarından alan türlerine, karmaşık ilişkilere, güçlü sorgu setlerine ve gelişmiş model özelliklerine kadar geniş bir yelpazeyi ele aldık.
Django Modelleri, uygulamanızın verilerini yapılandırma, sorgulama ve yönetme konusunda size inanılmaz bir esneklik ve güç sunar. Bu bilgileri özümseyerek ve pratik yaparak, kendi Django projelerinizde sağlam, ölçeklenebilir ve bakımı kolay veri modelleri oluşturmak için sağlam bir temel atmış olacaksınız. Unutmayın, iyi tasarlanmış bir veri modeli, başarılı bir uygulamanın temelidir.
