Django ORM (Nesne-İlişkisel Eşleme) ve QuerySets (Sorgu Setleri)
Bu bölümde Django'nun veritabanına nasıl bağlandığını ve veriyi nasıl sakladığını öğreneceğiz. Hadi başlayalım!
QuerySet (SorguSeti) Nedir?
QuerySet, esas olarak, verilen bir modelin nesnelerinin listesidir. QuerySet veritabanından veri okumamıza, veriyi filtrelememize ve sıralamamıza imkan sağlar.
En kolayı örnekle öğrenmektir. Hadi deneyelim, olur mu?
Django çekirdeği (shell)
Lokal konsolumuzu açalım (PythonAnywhere'de değil) ve şu komutu yazalım:
(myvenv) ~/djangogirls$ python manage.py shell
Etkisi aşağıdaki gibi olmalı:
(InteractiveConsole)
>>>
Şuan Django'nun interaktif konsolundayız. Python istemine benziyor, ama bazı ek Django büyüsüyle :) Tabi ki, burada da tüm Python komutlarını kullanabiliriz.
Tüm nesneler
Önce tüm gönderilerimizi görüntülemeyi deneyelim. Bunu aşağıdaki komut ile yapabiliriz:
>>> Post.objects.all()
Traceback (most recent call last):
File "<console>", line 1, in <module>
NameError: name 'Post' is not defined
Oops! Bir hata meydana geldi. Bize bir gönderi olmadığını söylüyor. Doğru - önce gönderiyi almayı unuttuk!
>>> from blog.models import Post
Post
modelini blog.models
model havuzundan kolayca kodumuza dahil ettik. Şimdi bütün gönderileri tekrar göstermeyi deneyelim:
>>> Post.objects.all()
[<Post: gönderi başlığım>, <Post: bir başka gönderi başlığı>]
Daha önce yarattığımız gönderilerin listesi! Bu gönderileri Django yönetici arayüzü kullanarak yaratmıştık. Şimdi ise Python kullanarak yeni gönderiler yaratmak istiyoruz, bunu nasıl yapabiliriz?
Nesne oluşturma
Veritabanına yeni bir gönderi eklemek için:
>>> Post.objects.create(yazar=ben, baslik=u'Örnek Başlık', yazi=u'Test')
Ancak bir eksiğimiz var: ben
. Gönderinin yazar özelliğine User
modelinden türetilen bir nesneyi parametre olarak vermemiz gerekiyor. Nasıl verebiliriz?
Öncelikle kullanıcı modelini dahil edelim:
>>> from django.contrib.auth.models import User
Veritabanımızda hangi kullanıcılar var? Şu şekilde görebiliriz:
>>> User.objects.all()
[<User: ahmet>]
Daha önce yarattığımız ayrıcalıklı kullanıcı! Şimdi veritabanından kullanıcı nesnesi alalım:
ben = User.objects.get(username='ahmet')
Gördüğünüz gibi, username
özelliği 'Ahmet' olan User
nesnesini get
ile aldık. Müthiş! Tabiki, kullanıcı adını kendi kullanıcı adınıza göre ayarlamalısınız.
Gönderimizi artık kaydedebiliriz:
>>> Post.objects.create(yazar=ben, baslik=u'Örnek Başlık', yazi=u'Test')
Yaşasın! Çalışıp çalışmadığını kontrol etmek ister misin?
>>> Post.objects.all()
[<Post: gönderi başlığım>, <Post: bir başka gönderi başlığı>, <Post: Örnek başlık>]
İşte bu kadar, listede bir gönderi daha!
Daha fazla gönderi ekle
Şimdi biraz eğlenenebiliriz ve nasıl çalıştığını görmek için daha fazla gönderi ekleyebiliriz. 2-3 tane daha ekleyin ve bir sonraki kısma devam edin.
Nesneleri filtrelemek
QuerySets in büyük bir parçası nesneleri filtreleyebilme kabiliyetidir. Diyelim ki, kullanıcı Ola tarafından yazılmış tüm gönderileri bulmak istiyoruz. Post.objects.all()
yapısı içindeki all
yerine filter
kullanacağız. Parantez içinde, bir blog gönderisinin sorgu setimizin içinde yer alması için hangi şartı(ları) sağlaması gerektiğini belirteceğiz. Örneğimizde, yazar
özelliği ben
nesnesine eşitti. Django'da bu filtre şöyle yazılır: yazar=ben
. Şuan bizim kod parçacığımız şöyle görünüyor:
>>> Post.objects.filter(yazar=ben)
[<Post: Örnek başlık>, <Post: Gönderi Numarası 2>, <Post: Üçüncü postum!>, <Post: Gönderinin dördüncü başlığı>]
Ya da belki title
alanında içinde 'başlık' kelimesini içeren tüm gönderileri görmek istiyoruz?
>>> Post.objects.filter(baslik__contains=u'başlık')
[<Post: Örnek başlık>, <Post: gönderinin dördüncü başlığı>]
Not
baslik
vecontains
arasında iki tane alt çizgi (_
) var. Django'nun ORM'i bu söz dizimini, özelliği ("baslik") ve operasyon veya filtreyi ("contains") ayırmak için kullanır. Sadece tek alt çizgi kullanırsanız, "FieldError: Cannot resolve keyword title_contains" hatası alırsınız.
Ayrıca yayınlanmış tüm gönderilerin bir listesini alabiliriz. Bunu geçmişte yayinlanma_tarihi
alanı belirtilmiş tüm gönderileri filtreleyerek yapıyoruz:
>>> from django.utils import timezone
>>> Post.objects.filter(yayinlanma_tarihi__lte=timezone.now())
[]
Maalesef, Python konsolundan eklediğimiz gönderi henüz yayınlanmadı. Bunu değiştirebiliriz! İlk olarak yayınlamak istediğimiz gönderinin bir örneğini alalım:
>>> post = Post.objects.get(baslik="Örnek başlık")
Ardından yayinla
metodu ile gönderiyi yayınlayalım!
>>> post.yayinla()
Şimdi yayınlanmış gönderileri tekrar almaya çalışalım (3 kez yukarı yön ve ardından enter
tuşuna basın):
>>> Post.objects.filter(yayinlama_tarihi__lte=timezone.now())
[<Post: Örnek başlık>]
Nesneleri Sıralama
QuerySets ayrıca nesne listesini sıralamanızı da sağlar. Nesneleri yaratilis_tarihi
özelliğine göre sıralamayı deneyelim:
>>> Post.objects.order_by('yaratilis_tarihi')
[<Post: Örnek başlık>, <Post: Gönderi Numarası 2>, <Post: Üçüncü postum!>, <Post: Gönderinin dördüncü başlığı>]
Başlangıçta -
ekleyerek sıralamayı tersine de çevirebiliriz:
>>> Post.objects.order_by('-yaratilis_tarihi')
[<Post: Gönderinin dördüncü başlığı>, <Post: Üçüncü postum!>, <Post: Gönderi Numarası 2>, <Post: Örnek başlık>]
Sorgu Setlerini Zincirlemek
Sorgu setlerini zincirleyerek beraber kullanabilirsiniz:
>>> Post.objects.filter(yayinlama_tarihi__lte=timezone.now()).order_by('published_date')
Zincirleme gerçekten çok güçlüdür ve oldukça kompleks sorgular yazmanıza imkan sağlar.
Güzel! Şimdi bir sonraki bölüm için hazırız. Çekirdeği kapatmak için, şunu yazalım:
>>> exit()
$