Herkese merhaba. Bugün ilk olarak Web’in temel çalışma prensipi olan Request-Response Döngüsünü’nden daha sonra bu döngünün Django ile geliştirilmiş sistemlerde nasıl yürütüldüğünden konuşacağız. Django size isteğinizin cevabını sunarken kaputun altında çok fazla iş yapmakta. Bu işleyişi tam olarak kavramak Django’ya hakimiyet seviyenizi yukarıya çekecek, daha hızlı geliştirme ve daha özgür bir geliştirme şansı verecektir. Hazırsanız başlayalım uzun bir yazı olacak! 🤔
Biraz bilgileri tazelemekte fayda var.
Web nasıl çalışır?
Web’in çalışma prensipi gayet basittir. Siz bir istek yaparsınız ve karşı taraf size bir cevap döner. Basit ama çok önemli bir prensiptir. Değiş tokuş gibi de denebilir. 2 ana nesne üstünden döner Request ve Response.
Fakat bu değiş tokuş yapılacakken belirli bir standartlar bütününe tabi olması gerekir. Bu standartlar bütününe ise HTTP diyoruz.
HTTP nedir?
Açılımı Hyper Text Transfer Protocol olan bu protokol yapılacak isteğin ve dönecek cevabın oluşturulması sırasında kullanılır. İstemci ve sunucu arasında konuşulan dildir de denebilir. Arama yapmak için Google’a girer ve arama kutusuna Django yazarsınız bu parametre isteğinize eklenir. Değerlendirme esnasında sunucu bu isteği alır,parametrelerinize göre işlem yapar ve cevabı size döner.
Yukarıda da bahsedildiği üzere iki ana nesnesi vardır. Şimdi bu 2 nesneyi inceleyecek olursak:
Request.
Bu nesne istemci tarafından yapılan isteğin bilgilerini ve verilerini tutar. Örneğin Twitter’da paylaşmak istediğiniz tatlı kedi fotoğrafı😅, istek yaptığınız cihazın IP adresi gibi veya sunucu ile nasıl bir iletişim kurmak istediğinizle alakalı olabilir. Bir şeyler oluşturmak veya silmek için mi istek yaptınız yada spesifik bir arama mı yapmak istiyorsunuz? Bunlar sunucuya request nesnesi üzerinden aktarılır. Sunucu işlemi yapar bir cevap üretir ve döner.
Response.
Sunucudan dönen cevabın niteliklerini taşır. Cevap gövdesinin hangi formatta istemciye sunulacağı, ne zaman yapıldığı, nereden sağlandığı veya başarı durumu gibi nitelikler içerir. Örneğin HTML formatında bir dosya dönmüş ise browser bunu yorumlar çıktıyı size sağlar.
Basit bir HTTP Response’nda döndürülen niteliklerinden bazıları.
Her şey güzel. Buraya kadar her şey tamamsa bu işleyişin Django’da nasıl yürütüldüğüne bakalım.
Django’daki Request Response Döngüsü
Django’nun istekleri alırken ve cevap dönerken arka tarafta bir çok iş yaptığından bahsetmiştik. İlk olarak Django uygulamanızın bir web sunucusu olmadığını ve doğrudan web sunucusu ile konuşamayacağını bilmemiz gerek. Bunun için ara bir katman daha dahil etmek zorundayız. Buna WSGI diyoruz. İleride açıklayacağım fakat önce bu döngünün bir diyagramını çizdim. Bu diyagram üzerinden adım adım konuşacağız. Bir VTR’miz var gelsin😂
Başlayabiliriz. İstemci bir istek yaptı ve bu bizim web sunucumuza ulaştı. Doğrudan uygulama ile konuşamayacağını biliyoruz. Bu yüzden WSGI adlı bir katmandan yararlanıyoruz.
WSGI (Web Server Gateway Interface) nedir?
WSGI yukarıda bahsedilen problemi çözmek için oluşturulmuş bir araçtır. Web sunucusunu web framework’üne bağlamak. Sunucu ve uygulama tarafı olarak 2 taraflı çalışır. WSGI yanıt üretmek için uygulamayı yürütür ve uygulamaya callback fonksiyonu sağlar. Bu fonksiyon yardımı ile de uygulamadan yanıtı alır devamında sunucuya oradan da istemciye dönmesini sağlar.
Kısacası dış dünya ile uygulamanızın köprüsüdür. WSGI bir Python standartı olup PEP 3333 ‘ te tanımlanmıştır.
İsteği aldık. WSGI tarafından bir Request objesi olusturuldu. Fakat Django’nun URL çözümleyicisine oradan view’a ve geri kalana devam edip bir cevap dönülmeden önce hala yapılması gereken işlemler var. Diyagramda da belirtildiği üzere bunlara middlewares diyoruz. Django katmanları üzerinden devam edelim.
Django Katmanları.
- Request middleware ‘ler ile kontrol.
- Url çözümlemesi.
- View’ın yürütülmesi.
- Context processor’ların çalıştırılması.
- Template renderer’ların çalıştırılması.
- Response middleware’ ler ile kontrol.
1) Request middlewares
Bir Django projesi oluşturduğunuzda settings.py dosyasına baktığınızda şu tanımlamaları görmüş olmalısınız.
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
Bunlara ara katmanlar diyoruz.
Bir istek geldiğinde ilk olarak bu katmanlarda değerlendiriliyor. Güvenlik,oturum,mesaj kontrolleri vs.
Fakat bu işlem 2 defa yapılıyor. Her istek geldiğinde ve her cevap dönüleceğinde ki tutarlılık sağlanabilsin.. Bu işlemlerden geçemeyen istekler için ise hata fırlatılıyor.
Baştan aşağıya doğru işlem bir işlem sırası ile işleniyor. Yani ilk olarak Security daha sonra Session ta ki Xframe katmanına kadar.
Buraya kadar yönetilen istek geçerli ise istek url çözümleyiciye geçiriliyor.
2) URL resolver.
ROOT_URLCONF = 'avesome_django.urls'
Url çözümleyici yukarıda tanımı gösterilen kök url dosyasını buluyor. Ve eğer var ise kök url’den dallanan diğer url dosyalarını da buluyor ve içeri dahil ediyor. Sonrasında gelen isteği parçalıyor ona göre hangi View’ın çalıştırılacağına karar veriyor ve isteği View’a geçiriyor. Örnek olarak aşağıda postId adlı bir parametre tanımlanmış ve View’ da karşılanmıştır.
path('edit/<int:postId>',dummy_view) def dummy_view(request, postId): pass
3) View logic , ORM
Burası bildiğiniz gibi iş mantığını kullandığımız katman. Bir istek bize ulaştı ve üzerinde çeşitli bilgiler barındırıyor olabilir. Bir form kaydedilmiş veya bir sorgu yollanmış olabilir. Örneğin bloğunuzda başlıkları aramak için bir arama kutucuğu var istemci bu form yardımıyla size ‘Python’ kelimesini yolladı. ORM yardımıyla bir sorgu yazmamız gerek ki istenilen özelliklere sahip veriyi elde edebilelim.
query = request.GET.get('query') qs = Post.objects.filter(title__icontains=query)
Bu yapı bizim için veritabanına gidecek ve şu sorguyu çalıştıracaktır.
SELECT ... WHERE title ILIKE '%Python%';
Ve dönen sonucu qs değişkenine atayacaktır.
4) Context processors.
Sadece bir template render etmiyorsanız her view neredeyse bir context döndürür. Context ‘ler veriyi template içerisinde kullanmamızı sağlar. Sözlük yapısında bir veri türüdür. Yani key:value şeklinde çalışır. Verilen key ile template içinde o veriye ulaşabilir ve sunum için işleyebilirsiniz. Örneğin yukarıdaki qs değişkeni için kullanım.
return render(request, list.html, context= {'object_list': qs})
Bir de her template’in döndürülmesi sırasında bağlamsal içerik üretmek için kullanabileceğimiz context_processor ‘lar vardır. Örneğin:
### devam ediyor 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ] ### devam ediyor
Sırayla işlenirler ve sizin view’dan dan döndürdüğünüz context ile birleşirler.
5) Template Renderer.
Template renderer ‘lar verilen template’i view’dan dönen context ve template tag leri yardımıyla oluşturur. Örneğin
{% for i in object_list %} <h1>{{i.title}}</h1> {% endfor %}
Dönen liste üzerinde for ile dolaşarak elementleri template ekleyebilirsiniz. Ayrcıa yerleşik olmayan filtreler de yazarak özelleştirmelerde bulunabilirsiniz.
Bu aşamada oluşturulan cevap Response objesine aktarılır. Sunum için yola çıkar.
6) Response middleware.
Cevap yine middleware ler yardımı ile kontrol edilir. Fakat bu sefer sondan başa doğru bir işlenme sırasını takip eder. Herhangi bir hata veya tutarsızlık olması durumunda hata fırlatır.
Bazı bilgileri Response objesine işler ve WSGI’nin ilk başta oluşturduğu callback fonksiyonu yardımıyla sunar.
Ayrıca kendimizde middlewarelar yazıp kullanabilirz. Böylece istek üzerinde kesinlikle bulunması istediğimiz veya istemediğimiz niteliklerin kontrolünü sağlayabiliriz. Fakat mantıksal açıdan doğru bir sıraya koymamız gerek. Biliyorsunuz ki baştan aşağı bir daha sonrasında ise sondan başa bir işlem kuyruğu bulunmakta. Araya girerken dikkatli olmamız gerekmekte. Tamamsak devam edelim.
WSGI dönen cevabı sunucuya o da kullanıcıya iletir.
Ve böylece bir request-response döngüsü sonlanmış olur. 🤔🤗
Sonuç olarak.
Artık bir Django projesinde yapılan isteklerin genel olarak nasıl değerlendirildiğini ve dönüş yapıldığını biliyoruz. Yukarıdaki her yapı kendi içinde de fazlasıyla derinleşiyor.
Ama Django’da tam anlamıyla özelleştirilmiş bir yapı kurmak istediğimizde nereye müdahele edeceğimiz konusunda bir fikir sahibi olmak zaman kaybetmeme açısından önemli.
Örneğin her template’de kullanmak istediğiniz değişkenler var siz hepsi için view’lar elle ekleme yapıyorsanız hata yapıyorsunuz demektir. Bir context_processor oluşturarak bir defa kod yazmak daha akıllıca olabilir.
Unutmayın ki
D(on’t) R(epeat) Y(ourself). 🙂
Bu arada yazın olduğu gibi Mustafa Akgül Özgür Yazılım Kış Kampı’nda da Django ile Web Programlamaya giriş sınıfındayım. Kahve içmek isterseniz buyurun beklerim 😊Herkese iyi günler..
Django’ya yeni başlayan biri olarak, Django”nun temel çalışma prensibinin anlaşılması açısından çok detaylı ve öğretici bir post olmuş. Malum bu tür detaylı bilgilendirme Türkçe olarak pek yok. Teşekkürler.
Seni tanımıyorum bir x okulda öğrenciyim ve django ödevim vardı. yazıların gerçekten kaliteli ve yol gösterici. emeğine saglık. beni de blog yazmaya başlatmaya teşvik ettin arkadasım 🙂 kolaygelsin