Django ORM 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 (SorguSeti), esas olarak, verilen bir modele ait nesnelerin listesidir. QuerySet veritabanından veri okumamıza, veriyi filtrelememize ve sıralamamıza imkan sağlar.

En kolayı örnek ile öğrenmektir. Hadi deneyelim, olur mu?

Django shell (kabuk)

Bilgisayarımızdaki konsolu açalım (PythonAnywhere'dekini değil) ve şu komutu yazalım:

(myvenv) ~/djangogirls$ python manage.py shell

Etkisi aşağıdaki gibi olmalı:

(InteractiveConsole)
>>>

Şu an Django'nun etkileşimli konsolundayız. Python istemine benziyor, ama biraz Django büyüsü eklenmiş :) Kuşkusuz burada da Python komutlarının tümünü kullanabiliriz.

Tüm nesneler

Önce tüm post'larımızı 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

Ahh! Bir hata meydana geldi. Bize Post'un tanımlı olmadığını söylüyor. Bu doğru, öncesinde post'u dahil etmeyi (import) unuttuk!

>>> from blog.models import Post

blog.models'dan Post modelini dahil ettik (import). Tekrar bütün post'ları görüntülemeyi deneyelim:

>>> Post.objects.all()
<QuerySet [<Post: Gönderi başlığım>, <Post: Diğer bir gönderi başlığı>]>

Bu daha önce oluşturduğumuz post'ların listesi! Bu post'ları Django admin arayüzü ile oluşturduk. Fakat şimdi Python kullanarak yeni post'lar oluşturmak istiyoruz, peki bunu nasıl yaparız?

Nesne oluşturma

Veritabanına yeni bir gönderi eklemek için:

>>> Post.objects.create(author=ben, title='Harika bir gönderi', text='Ne desem bilemedim')

Ancak bir eksiğimiz var: ben. Gönderinin author (yazar) özelliğine User (kullanıcı) modelinden türetilen bir nesneyi parametre olarak vermemiz gerekiyor. Nasıl verebiliriz?

Öncelikle User (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()
<QuerySet [<User: zeynep>]>

Bu daha önce yarattığımız süper kullanıcı (superuser)! Şimdi bu kullanıcının örneğini (instance) alalım (bu satırı kendi kullanıcı adınızı kullanmak için değiştirin):

ben = User.objects.get(username='zeynep')

Görebildiğiniz gibi, şimdi kullanıcı adı 'zeynep' olan bir User aldık. Temiz!

Gönderimizi artık kaydedebiliriz:

>>> Post.objects.create(author=ben, title='Harika bir gönderi', text='Ne desem bilemedim')
<Post: Harika bir gönderi>

Yaşasın! Çalışıp çalışmadığını kontrol etmek ister misin?

>>> Post.objects.all()
<QuerySet [<Post: Gönderi başlığım>, <Post: Diğer bir gönderi başlığı>,<Post: Harika bir gönderi>]>

İşte bu kadar, listede bir gönderi daha!

Daha fazla post ekle

Şimdi daha fazla post ekleyerek biraz eğlenebilir ve nasıl çalıştığını görebiliriz. İki veya üç tane daha ekleyelim ve sıradaki bölüme geçelim.

Nesneleri filtrelemek

QuerySet'lerin büyük bir bölümü nesneleri filtreleme yeteneğidir. Diyelim ki, Zeynep tarafından yazılmış tüm post'ları (gönderileri) bulmak istiyoruz. Post.objects.all() içindeki all yerine filter kullanacağız. Parantez içine istediğimiz blog gönderilerinin sağlaması gereken şartları belirteceğiz. Örneğimizde, author ben'e eşitti. Django'da bu filtreyi şöyle yazıyoruz: author=ben. Şu an kod parçacığımız şöyle görünüyor:

>>> Post.objects.filter(author=ben)
[<Post: Gönderi 1>, <Post: Gönderi 2>, <Post: Harika bir gönderi>, <Post: Nefis bir gönderi>]

Ya da belki title (başlık) alanında içinde 'Nefis' kelimesini içeren tüm gönderileri görmek istiyoruz?

>>> Post.objects.filter(title__contains='Nefis')
[<Post: Nefis bir gönderi>]

Not title ve contains arasında iki tane alt çizgi (_) var. Django'nun ORM'i bu söz dizimini, özelliği ("title") ve operasyon veya filtreyi ("contains") ayırmak için kullanır. Eğer sadece tek bir alt çizgi kullanırsanız, "FieldError: Cannot resolve keyword title_contains" şeklinde bir hata alacaksınız.

Ayrıca yayınlanmış tüm post'ların bir listesini alabiliriz. Bunu published_date (yayinlanma_tarihi) alanı geçmiş bir tarih olan tüm gönderileri filtreleyerek yapıyoruz:

>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet []>

Maalesef python konsolundan eklediğimiz post (gönderi) henüz yayınlanmadı. Fakat bunu değiştirebiliriz! Önce yayınlamak istediğimiz bir gönderi nesnesi bulalım:

>>> post = Post.objects.get(title="Harika bir gönderi")

Ardından publish (yayinla) methodu ile gönderiyi yayınlayalım:

>>> post.publish()

Şimdi yayınlanmış gönderileri tekrar almaya çalışalım (3 kez yukarı ok tuşuna ve ardından enter tuşuna basın):

>>> Post.objects.filter(published_date__lte=timezone.now())
[<Post: Harika bir gönderi>]

Nesneleri Sıralama

QuerySets ayrıca nesne listesini sıralamanızı da sağlar. Nesneleri created_date (yaratilma_tarihi) özelliğine göre sıralamayı deneyelim:

>>> Post.objects.order_by('created_date')
[<Post: Gönderi 1>, <Post: Gönderi 2>, <Post: Harika bir gönderi>, <Post: Nefis bir gönderi>]

Başına - ekleyerek sıralamayı tersine de çevirebiliriz:

>>> Post.objects.order_by('-created_date')
[<Post: Nefis bir gönderi>, <Post: Harika bir gönderi>, <Post: Gönderi 2>, <Post: Gönderi 1>]>

QuerySets (SorguSetlerini) Zincirlemek (Chaining)

Sorgu setlerini zincirleyerek beraber kullanabilirsiniz:

>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
<QuerySet [<Post: Gönderi 2>, <Post:Harika bir gönderi!>, <Post: Nefis bir gönderi>, <Post: Gönderi 1>]>

Zincirleme gerçekten çok güçlüdür ve oldukça karmaşık sorgular yazmanıza imkan sağlar.

Güzel! Şimdi bir sonraki bölüm için hazırız. Komut satırını kapatmak için, şunu yazalım:

>>> exit()
$

Last updated