Django’da signals kullanımı

Django’da signals kullanımı
Django’nun admin paneli çoğu durum için yeterli olsa da biraz değişik bir şey yapmak istediğinizde tutorial’da bahsedilenden farklı bir işlem yapmanız gerekiyor. Sinyaller (signals), Django’nun bu durumda yardımcı olabilecek bir özelliği.

Sinyaller, uygulamada belirlenen alıcıların göndericilerin yaptığı işlemlerden haberdar olmasını sağlar. Bu ne demek biraz açalım; mesela bir modeliniz var ve bu model save edildiği zaman başka bir fonksiyon çağırmak istiyorsunuz. Modelinizi gönderici (sender) olarak belirleyip olurturduğunuz diğer bir fonksiyonu da alıcı (receiver) olarak gösterebilirsiniz.

Django’da kendiniz sinyal fonksiyonlarınızı oluşturabileceğiniz gibi hazırda bulunan sinyaller de mevcut. Modellerin kaydedilme esnasında (öncesinde ve sonrasında) tetiklenen sinyaller ve http isteği başlarken ve biterken tetiklenen sinyaller gibi.

Bir örnek vermek gerekirse:

Ekipman isimli bir modelimiz olsun. Bu modelde her değişiklik yapıldığında bunu ayrı bir tabloda tutmak istiyoruz. Böylelikle ekipmanda yapılan her değişikliği kayıt altında tutabileceğiz.

class Ekipman(models.Model):
    seri_no = models.CharField(max_length=20)
    bulundugu_yer = models.CharField(max_length=20)
    tamirde = models.BooleanField()
    notlar = models.TextField(blank=True)

Gecmis isimli bir de tablomuz var. Buna da yapılan değişiklikleri kaydedeceğiz.

class Gecmis(models.Model):
    ekipman = models.ForeignKey(Ekipman)
    seri_no = models.CharField(max_length=20)
    bulundugu_yer = models.CharField(max_length=20)
    tamirde = models.BooleanField()
    notlar = models.TextField(blank=True)

Şimdi de kayıt işlemini gerçekleştirecek fonksiyonumuzu oluşturalım.

def GecmisTut(sender, **kwargs):
    ekipman = kwargs['instance']
    gecmis = Gecmis(ekipman = ekipman, \
    seri_no = ekipman.seri_no, \
    bulundugu_yer = ekipman.bulundugu_yer, \
    tamirde = ekipman.tamirde, \
    notlar = ekipman.notlar)
 
    ekipman.save()

Alıcı fonksiyonu her zaman sender ve kwargs parametrelerini almalıdır. sender parametresi göndericinin sınıfını (instance’ını değil) tutar. Oluşturduğumuz modelin kendisini (instance’ını) almak için kwargs içindeki instance anahtarını kullanmamız gerekir.

Bu fonksiyonu iki şekilde gönderici ile bağlayabiliriz. Model kaydedildikten sonra alıcının çağırılmasını istediğimize göre:

from django.models.signals import post_save

def GecmisTut(sender, **kwargs):
    ekipman = kwargs['instance']
    gecmis = Gecmis(ekipman = ekipman, \
    seri_no = ekipman.seri_no, \
    bulundugu_yer = ekipman.bulundugu_yer, \
    tamirde = ekipman.tamirde, \
    notlar = ekipman.notlar)
 
    ekipman.save()
 
post_save.connect(GecmisTut, sender=Gecmis)

Veya fonksiyonu bir decorator ile kullanalım:

from django.models.signals import post_save

@receiver(post_save, sender=Ekipman)
def GecmisTut(sender, **kwargs):
    ekipman = kwargs['instance']
    gecmis = Gecmis(ekipman = ekipman, \
    seri_no = ekipman.seri_no, \
    bulundugu_yer = ekipman.bulundugu_yer, \
    tamirde = ekipman.tamirde, \
    notlar = ekipman.notlar)
 
    ekipman.save()

şeklinde kullanabiliriz.

Django’da Admin panelinde modelleri Türkçe çoğul yapma

Django’da admin panelinde modeller verdiğiniz ad ne olursa olsun çoğul yapılırken sonuna ‘s’ takısı alır (örneğin Personels). Oysa ki biz Personel modelini admin panelinde Personeller olarak görmek isteyebiliriz.

Bu durumda Personel modeline aşağıdaki sınıfı eklemeniz yeterli olacaktır:

class Personel(models.Model):
    .......
    class Meta:
        verbose_name_plural = "Personeller"

Django’da QuerySet’ler 2 – Filtreleme

Queryset’lerde alınan veri üzerinde filtreleme işlemi aşağıdaki örnekte olduğu gibi yapılabilir.

kisiler = Kisi.objects.all()
kisiler.filter(isim='Ahmet')


Zincirleme filtre de aşağıdaki gibidir.

kisiler = kisiler.filter(yas=20)
kisiler = kisiler.filter(isim__startswith='A')


Dikkat edilmesi gereken nokta bu query’ler çalıştırıldığında veritabanı ile herhangi bir bağlantı kurulmamasıdır (şu ana kadar sadece veriyi çekecek olan query’i oluşturduğumuzu düşünebilirsiniz). Bağlantı queryset’ler içerisindeki bilgiye ulaşılmaya çalışıldığında kurulur.

kisiler = Kisi.objects.filter(isim__startswith='A')
kisiler = kisiler.filter(soyad__contains='E')
for kisi in kisiler:
print kisi.isim


Yukarıdaki kod çalıştırıldığında belirtilen filtreler ile getirilen sonuçları ekrana yazar. Bu sırada veritabanı ile sadece bir kere bağlantı kurulur.

Django’da QuerySet’ler 1

Django’da QuerySetler

Django’da queryset’ler çağırıldığında cache’de tutulurlar. Böylece çağırılan queryset tekrar kullanılarak database üzerindeki yük azaltılmış olur.

Aşağıdaki query’ler çalıştırıldıklarında veritabanı ile iki kere bağlantı kurarak toplamda iki ayrı sorgu çalıştırır.

q = kisi.isim for kisi in Kisi.objects.all()
q = kisi.yas for kisi in Kisi.objects.all()


Bunun yerine daha az kaynak tüketen aşağıdaki yol izlenebilir.

kisiler = Kisi.objects.all()
kisi.isim for kisi in kisiler
kisi.yas for kisi in kisiler

Bu şekilde veritabanı ile sadece bir defa bağlantı kurularak queryset cache’e alınır.