Django’da proje geliştirirken bir noktada hepimiz aynı duvara toslarız: Sitenin her sayfasında (örneğin navbar’da, sidebar’da veya footer’da) göstermemiz gereken bazı dinamik veriler vardır. Kategori listeleri, sepetteki ürün sayısı, okunmamış bildirimler veya genel site ayarları gibi…
İlk başlarda bu verileri her View fonksiyonunun içinde tek tek çağırıp template’e göndermek göze batmaz. Ancak proje büyüdükçe context sözlükleri şişmeye başlar ve kod tekrarı (DRY - Don’t Repeat Yourself ihlali) can sıkıcı bir hal alır.
İşte Django’nun bu duruma getirdiği şık çözümün adı Context Processor.
Context Processor Aslında Nedir?
Çok temel düzeyde düşünürsek; Context Processor sadece bir HTTP request nesnesi alan ve döndürdüğü sözlüğü (dictionary) tüm şablonların (templates) kullanımına açan basit bir Python fonksiyonudur.
Zaten farkında olmadan bunları sürekli kullanıyoruz. Şablonlarda hiçbir view’dan veri göndermediğiniz halde {{ user.is_authenticated }} veya {{ request.path }} yazabildiğinizi düşünün. Bunlar Django’nun varsayılan context processor’larının arka planda çalışmasının bir sonucudur.
Kendi Context Processor’ımızı Yazalım
Diyelim ki blogumuzun her sayfasında göstermek istediğimiz site ayarları ve o anki yıl bilgisi var. Bunu adım adım projemize nasıl entegre edeceğimize bakalım.
1. Fonksiyonu Oluşturmak
Öncelikle app dizininizin içinde (ben bu tarz genel yapıları genellikle core veya common gibi bir app içinde tutarım) context_processors.py adında yeni bir dosya oluşturun:
| |
2. Django’ya “Bunu Kullan” Demek
Yazdığımız fonksiyonun projenin her yerinde çalışması için onu settings.py dosyasındaki TEMPLATES ayarının içine kaydetmemiz gerekiyor.
| |
3. Template İçinde Doğrudan Kullanım
Artık bu değişkenleri view üzerinden yollamanıza gerek yok. Projedeki herhangi bir HTML dosyasında (özellikle base.html gibi ana iskelet dosyalarında) direkt çağırabilirsiniz:
| |
Dikkat: Performans Tuzağına Düşmeyin
Context Processor’lar hayat kurtarır ama aynı zamanda dikkatsiz kullanıldığında projenizin performansını bir anda yerle bir edebilir.
Neden mi? Çünkü settings.py dosyasına eklediğiniz bir context processor, sitenizde render edilen istisnasız her bir sayfa için yeniden çalıştırılır. Eğer bu fonksiyonun içine gidip Article.objects.all() gibi ağır bir veritabanı sorgusu atarsanız, sitenize giren her kullanıcı, her sayfa değişiminde o devasa sorguyu veritabanında tekrar tetikler.
Eğer veritabanından veri çeken bir context processor yazmanız gerekiyorsa (ki dinamik menüler için çoğu zaman gerekecektir), o sorguyu mutlaka Django’nun Cache (Önbellekleme) mekanizması ile sarmalamanız şarttır. Aksi takdirde veritabanınız gereksiz yük altında ezilir.
Performans Dostu Çözüm: Context Processor ve Cache (Önbellekleme)
Eğer Context Processor içinde veritabanı sorgusu yapmanız gerekiyorsa (örneğin tüm sayfalarda dinamik bir kategori menüsü göstermek için), bunu çıplak bir ORM sorgusuyla yapmak sitenizi yavaşlatır. Her sayfa yenilendiğinde aynı kategoriler için veritabanına tekrar tekrar gidilir.
Çözüm, sonucu belirli bir süreliğine bellekte (RAM) tutmaktır. Django’nun yerleşik cache modülünü kullanarak bunu çok zarif bir şekilde çözebiliriz.
Önbellekli Context Processor Örneği
Diyelim ki blogumuzun sidebar‘ında göstermek için aktif kategorileri çeken bir fonksiyon yazıyoruz. Kodumuz şu şekilde olmalı:
| |
Bu Kod Bize Ne Kazandırdı?
- Veritabanı Rahatladı: Kullanıcı sitenizde 50 farklı sayfayı gezse bile, veritabanına sadece 1 kez sorgu atılır. Kalan 49 sayfa gösteriminde veriler ışık hızıyla RAM’den (önbellekten) gelir.
- Ölçeklenebilirlik: Sitenizin trafiği aniden artsa bile menü sorguları veritabanını kilitlemez.
Küçük Bir İpucu: Django varsayılan olarak Local Memory Cache kullanır ve küçük projeler için yeterlidir. Ancak projeyi gerçek bir sunucu ortamına taşıdığınızda, önbellek verilerini yönetmek için Redis veya Memcached kullanmak endüstri standardıdır. Özellikle geliştirme ve canlı ortamlarınızı izole bir şekilde yönetiyorsanız, mimarinize küçük bir Redis konteyneri eklemek bu sistemi kusursuz hale getirecektir.
