Django’yu öğrenmek isteyenlerin kafasını karıştıran konseptlerden biri, basit bir Django projesinin hiyerarşik yapısı ve bunun nasıl çalıştığıdır. Bir Django projesi başlatmak için önce sanal bir ortam oluşturun, bu ortama Django’yu yükleyin, ardından şu komutu çalıştırın:

django-admin startproject myproject

Bu komutu çalıştırdığınız dizinde myproject isimli bir klasör oluşacaktır. Bu klasöre girerseniz ana dizinde manage.py isimli bir dosya göreceksiniz. Bu dosyayı kullanarak Django’yu ayağa kaldırabilirsiniz:

python manage.py runserver

Eğer Django’nun komut satırında size verdiği adrese giderseniz, yerel ortamınızda çalışan, Django tarafından hazırlanmış bir web sayfası göreceksiniz.

Eğer oluşturulan dosya yapısını incelerseniz, Django’nun sırf bunu yapabilmesi için tam altı dosya ve kök dizin dahil 2 dizin oluşturduğunu göreceksiniz. İşin ilginç tarafı, henüz ekrana istediğimiz yazıyı bile bastıramadık, bunu yapmak için birkaç dosya daha oluşturmamız gerekecek.

Şimdi kolları sıvayıp bir merhaba dünya çıktısı almaya çalışalım. Bunu yapmak için önce projemizde bir ‘app’ (uygulama) oluşturmamız gerekiyor. Bu aşamada app’leri Python modülleri olarak düşünebilirsiniz. Yani merhaba dünya çıktısı vermekle görevli bir modül oluşturmamız gerekiyor. Bunu yapmak için şu komutu proje ana dizininde çalıştırın:

python manage.py startapp helloworld

Bu komutu çalıştırdıktan sonra, manage.py dosyası ile aynı seviyede helloword isimli bir dizin oluşmuş olacak. Bu dizinin içinde yine yedi tane yeni Python dosyası oluşacak. Yeter mi? Yetmez, zira Django bir app modülü içinde urls.py dosyasını oluşturmuyor, bu dosyayı da elle oluşturmak gerekiyor; o zahmete ve gerekliliğinin sebebine şimdilik girmeyelim.

Merhaba dünya serüvenini sona erdirmek üzere, views.py dosyasında şu yapıyı oluşturun:

from django.http import HttpResponse


def index(request):
    return HttpResponse("Hello World!")

E tabii bu mesajın hangi URL’den verileceğini belirtmemiz gerekiyor (zira yukarıda böyle bir bilgi yok fark ettiyseniz). Bunun için de, myproject dizini içindeki urls.py içine de bir referans eklememiz gerekiyor:

from django.contrib import admin
from django.urls import path

from helloworld.views import index

urlpatterns = [
    path("", index),
    path("admin/", admin.site.urls),
]

Şimdi tekrar yerel ortamı ziyaret ederseniz ‘Hello World’ yazısının bizi karşıladığını göreceksiniz.

Bu aşamada “Yahu altı üstü bir merhaba dünya için bu kadar zahmete (4 dizin, 13 dosya) gerek var mıydı? Dosyaların çoğunu kullanmadık bile?” demenizi bekliyorum. Eğer önceden Flask veya Express gibi microframework’lar kullandıysanız tek dosyada bu işin hallolduğunu bilirsiniz.

Aslında bu örnek için bu dosyaların çoğuna ihtiyacımız yok, hatta hepsini silip tek dosyada da işinizi halledebilirsiniz. Mesela şu kodu bir Python dosyasına yazıp, komut satırından yine runserver diyerek çalıştırabilirsiniz:

import sys

from django.conf import settings
from django.http import HttpResponse
from django.urls import path

settings.configure(DEBUG=True, ROOT_URLCONF=__name__)


def index(request):
    return HttpResponse("Hello World!")


urlpatterns = [path("", index)]

if __name__ == "__main__":
    from django.core.management import execute_from_command_line

    execute_from_command_line(sys.argv)

Gerçek hayatta denemeyiniz.

Bu aşamada bu dosyaların gerekliliğini anlamak için Django’nun geliştirilme felsefesini anlamamız gerekiyor.

Monolithic (yekpare) dizayn ve “Batteries included” felsefesi

Bir backend web framework’tan minimum beklentimiz, istediğimiz URL’leri tanımlayabilmek ve bu URL’leri bir takım fonksiyonlarla ilişkilendirmektir. Bunu yaparken de çeşitli HTTP yapılarının soyutlanmış bir şekilde elimize ulaşmasını isteriz; örneğin request header’lerini kolayca bulabilmek gibi.

Hakikaten de, çoğu web framework bunu sağlar, fakat daha kompleks işler yapmak istediğiniz zaman üçüncü parti bir kütüphane kullanmanız gerekir. Örneğin database bağlantısı yapmak ve tablolar oluşturmak için muhtemelen bir ORM kütüphanesi kurmanız gerekir.

Diyelim ki ORM kütüphanesini kurdunuz, bu sefer de basit kullanıcı giriş/çıkış/oturum işlemleri yapmak istiyorsunuz; e bunu yapmak için de bir başka kütüphaneye ihtiyacınız var.

Kullanıcı giriş çıkış işlemi güvenlik konusunda pür dikkat gerektirir o yüzden yine üçüncü parti bir güvenlik kütüphanesi de kurmanız gerekti. Tam bunları yaparken fark ettiniz ki, kullanıcıdan aldığınız veriyi hem sanitize etmeniz hem de doğrulamanız gerekiyor, o yüzden bir tane de validation kütüphanesi kurdunuz.

İşte Django burada diyor ki: kardeş sen bu kütüphanelerle hiç uğraşma, ben bunların hepsini ve daha fazlasını senin için yaptım; sen zaten birbirine yamaladığın kütüphanelerle muhtemelen daha kötü bir stack oluşturdun. Sen benim hazır kodumu kullan; git bussiness logic’ini yaz.

Nedir mesela Django’nun verdiği şeyler? En temelinde kocaman bir ORM veriyor Django. Öyle ki bu ORM Django’nun neredeyse yarısını oluşturuyor, zira bütün workflow’lar (kullanıcı işlemleri, validation, admin integration) ORM’un etrafında tasarlanmış.

Tabii ki her use case için bu mükemmel bir tarif değil bu, bazen gerçekten de o kadar soyutlama katmanına ve kütüphaneye gerek duymuyoruz. Bazen de gerçekten kendi stack’imizi oluşturmak, özgür olmak istiyoruz.

Bu demek değil ki Django bize özgürlük tanımıyor, eğer beğenmediğiniz bir yapı varsa bunu çıkartıp yerine üçüncü bir parti kütüphane alabiliyorsunuz. Her şey app dediğimiz plug-in sistemine bağlı.

Django’nun bu felsefesini biraz irdelediğimize göre, gelin şu başlangıç projesinde oluşturulan yapıya, ve bu yapıdaki dosyaların ne işe yaradığına göz atalım. Proje yapısı şu an da böyle gözüküyor:

myproject/
├── helloworld
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── manage.py
└── myproject
    ├── __init__.py
    ├── asgi.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py

3 directories, 14 files

En temel olarak manage.py dosyasından başlayalım; bu dosya Django’yu serve etmek için gereken management komutunu çalıştırmaya yarıyor, aynı zamanda Django’nun pek çok command line gereçlerini bu modül yoluyla çağırabiliyoruz. Mesela runserver ve startapp komutlarını yukarıda görmüştünüz.

myproject dizinini inceleyecek olursak, settings.py Django uygulamamıza ait tüm ayarları içeren bir dosya, bunda hem kendimizin ürettiği hem de Django’ya ve diğer üçüncü parti kütüphanelere ait ayarları yönetebiliyoruz. urls.py projenin ana (root) URL dağıtımını gerçekleştiren modül. Burada belirlediğimiz namespace’lere (yani app’lerimize) URL ataması yapabiliyoruz.

asgi.py ve wsgi.py Django projemizi deploy ederken gereken olan modüller; özetle bu modüller Python uygulamaları ile web serverlerin iletişim kurabilmesi için oluşturulmuş bir standardı yerine getirmek için varlar.

Şimdi helloword app’imize bir bakalım.

  • apps.py Bu dosya, app’e ait ayarları ve yapılandırmayı içeriyor. Burada app’imizin okunabilir ismini ve kod adını belirleyebiliriz.

  • models.py Bu app’e ait modelleri yani database tablolarının tanımlarını içeren modül; app’i yeni oluşturduğumuz için diğer tüm modüller gibi burası boş. migrations klasörü, model eklediğiniz takdirde, database şemasının zamanla değişimini tutuyor bu sayede database’i olan gelişmeleri ileri ve geriye dönük olarak takip edebiliyoruz.

  • tests.py bu uygulamaya ait testlerini içeriyor.

  • views.py bu uygulamaya ait request karşılayıp response dönecek fonksiyonları içeriyor; yani kullanıcıları karşılayacak logic’iniz buradan başlıyor.

  • admin.py Django’nun admin sayfasında gözükecek modellerinizi ayarlamak için kullanacağınız modül burası.

App’leriniz için bu modüllerin çoğunu kaldırabilirsiniz, mesela app’iniz model veya view içeriyor olmak zorunda değil. Elinizde bir apps.py olması yeterli.

İşte bir Django projesinin yapısı böyle. Modülleri oradan buraya taşıma imkanımız da var, illa ki bu yapıda kalmak durumunda değilsiniz, fakat eninde sonunda buna benzer bir yapıya kavuşuyorsunuz. Django geliştiricileri bu yapıyı bize sunmuşlar, ister kullanın ister kullanmayın; internette pek çok farklı Django proje yapısı bulabilirsiniz.

Ben şahsen bu yapıda myproject içindeki dosyaları bir üst dizine, app’lerle aynı seviyeye taşıyorum; bunların ayrı bir klasörde durması garip geliyor.