Merhaba değerli e-bergi okurları! Bu yazıda sizlere Django’da kullanılan ve çoğunluk tarafından kabul görmüş yöntemlerden bahsedeceğim. Projenin yapısı ne şekilde oluşturulmalı, hangi uygulamalar kullanılmalı vb Django ile bir web projesine başlarken muhtemelen aklımıza takılacak soruların cevaplarını vermeye çalışacağım. En başta belirtmek isterim ki bu yazıda bahsedilen yanlışlar projenin çalışmasını engelleyecek şeyler değiller. Özellikle büyük bir projeye başlarken dikkat edilirse ilerde değişiklik yaparken veya yeni özellik eklerken kolaylık sağlayacağı düşünülen tercihlerden bahsedeceğim.

Öncelikle eğer hiç Django ile uygulama geliştirmediyseniz, dergimizin eski sayılarından bu yazıyı okumanızı tavsiye ederim. Bunun dışında Django’nun internet sitesinden tutorialları bitirmiş olmanız da bu yazıda bahsedilenleri daha iyi kavramanız adına faydalı olacaktır. Çünkü yazı boyunca Django’yu bildiğinizi varsayarak bilgi vereceğim.

Kodlama Tarzı

Büyük projelere başlamadan önce kodu ne tarzda yazacağına karar vermek projenin geliştirme açısından geleceği için önemlidir. İlerde başka bir geliştiricinin kodu incelediğinde nerde ne yapıldığını anlaması için belirli kurallara uyarak kod yazmak tüm geliştiricilere kolaylık sağlar. Her yazılım projesinde olduğu gibi Django projelerinde de değişken isimlerini kısaltmaktan kaçınılmalı, tüm fonksiyon isimleri açık bir şekilde yazılmalı, sınıfların ve fonksiyonların dökümantasyonu tamamlanmalıdır.

Django’dan bağımsız olarak Python projelerinde genel olarak PEP8 kodlama tarzı kullanılmakta. PEP8’in ise en bilindik kuralları

  • Her girinti düzeyi (tab) için 4 boşluk kullanılmalı
  • Tüm fonksiyon veya sınıf tanımlarından önce 2 satır boşluk olmalı
  • Sınıf içerisindeki fonksiyonların arasında 1 satır boşluk olmalı

Django’da kullandığımız modüllerin import edilme sıraları ise

  1. Standart kütüphaneler
  2. Django core (çekirdek) modülleri
  3. Üçüncü şahıs (third party) uygulamalar
  4. Kendi modüllerimiz

şeklinde olmalıdır.

Örneğin:

from math import sqrt (1)
from django.db import models (2)
from django_extensions.db.models import TimeStampedModel (3)
from dergi.models import Yazar (4)

Kendi oluşturduğumuz uygulamalarda aynı uygulamanın bir başka dosyasından import etme durumunda paketin (uygulamanın) adını açık bir şekilde yazmamalıyız. Aksi durumda paketin adını değiştirmemiz gerektiğinde çok sayıda dosyada değişiklik yapmak zorunda kalabiliriz. dergi adında oluşturduğumuz bir Django uygulamasından bir dosyada yine dergi uygulamasının bir modelini import ederkenki muhtemel kullanımlar:

from dergi.models import Yazar (yanlış)
from .models import Yazar (doğru)

Python modüllerini import ederken en çok yapılan yanlışlardan biri de tüm modülü * ile import etmek. Bu kullanım (from dergi.models import *) döngüsel bağımlılığa (circular dependency) yatkın bir yapıya sebep olacağından küçük bir değişiklik bile tüm sitenin çalışmasına engel olabilir.

Daha fazla bilgi için Django’nun sitesinde bu sayfayı inceleyebilirsiniz: https://docs.djangoproject.com/en/1.6/internals/contributing/writing-code/coding-style/

Proje Yapısı

Projeyi geliştirirken kullanılan sürüm kontol sisteminin kök dizinini projenin kök dizini kabul edersek projemizi şu şekilde yapılandırabiliriz:

● repository kök dizini
  ○ django projesi kök dizini
    ■ konfigürasyon kök dizini
    ■ uygulamalar kök dizini

Repository kök dizininde fazladan README.rst, .gitignore, requirements.txt gibi daha genel dosyalar olabilir. Projenin kök dizininde ise yukarıdakilerin dışında media, static gibi klasörlerin yanısıra tüm sitede kullanılan template’lar da yer alabilir.

Örneğin:

● ebergi-git/ (ebergi’nin git repository adı)
  ○ README.rst
  ○ .gitignore
  ○ requirements.txt
  ○ Makefile
  ○  ebergi-site/ (django projesi)
    ■ manage.py
    ■ media/
    ■ ebergi-site/ (projenin içindeki konfigürasyon dizini)
      ● __init__.py
      ● urls.py
      ● wsgi.py
      ● settings/
        ○ base.py
        ○ dev.py
        ○ prod.py
    ■ apps/ (projeye ait django uygulamalarının bulunduğu dizin)
      ● dergi/ (yazıların ve yazarların bulunduğu uygulama)
        ○ __init__.py
        ○ admin.py
        ○ models.py
        ○ views.py
        ○ tests.py
        ○ urls.py
        ○ managers.py
      ● uyelik/ (kullanıcıların aboneliğini yöneten uygulama)
        ○ __init__.py
        ○ admin.py
        ○ models.py
        ○ views.py
        ○ tests.py
        ○ urls.py
        ○ managers.py

Bu yapıyı yazının ileri bölümlerinde daha ayrıntılı inceleyeceğiz.

Settings Dosyaları

Örnek proje yapımızda görebileceğiniz gibi birden fazla settings dosyamız mevcut. Normalde bir Django projesi başlattığımızda elimizde sadece bir adet settings dosyası olurdu fakat bu durumda siteyi farklı ortamlarda çalıştırmak için ya sürekli kodu değiştirmek ya da dosya içinde her ortam için bir kontrol eklemek gerekirdi. Bunun yerine siteyi çalıştıracağımız her ortam için farklı birer settings dosyası oluşturuyoruz. Ortak olan ayarları da base.py dosyasına ekliyoruz. Sunucuyu çalıştırırken de settings dosyamızın yerini belirtiyoruz: python manage.py runserver --settings=ebergi.settings.dev

Böylece her ayrı sunucu bilgisayarda veya geliştirici ortamında farklı ayarlar kullanabiliyoruz. Örneğin:

base.py

INSTALLED_APPS = (
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 ‘dergi’,
 ‘uyelik’
)

dev.py

from .base import *
DEBUG = True
DATABASES = {
 'default': {
  'ENGINE': 'django.db.backends.postgresql_psycopg2',
  'NAME': ‘ebergi_db’,
  'USER': 'murataydos',
  'PASSWORD': '1234',
  'HOST': 'localhost',
  'PORT': '',
  }
}

prod.py

from .base import *
DEBUG = False
DATABASES = {
 'default': {
  'ENGINE': 'django.db.backends.postgresql_psycopg2',
  'NAME': ‘ebergi’,
  'USER': ‘admin’,
  'PASSWORD': 'admin’,
  'HOST': 'localhost',
  'PORT': '',
  }
}

Requirements Dosyaları

Sistemimize yüklediğimiz tüm uygulamaları herhangi bir sunucu değişikliği sırasında tekrar kurmakta sıkıntı çekmemek ve unutmamak için gerekli tüm uygulamaları bu dosyaların içine ekliyoruz. Örnek proje yapımızda sadece bir adet requirements.txt olsa da o dosya yerine requirements klasörü oluşturup içine aynı settings klasöründe olduğu gibi base.txt, dev.txt, prod.txt gibi farklı requirements dosyaları oluşturabilirsiniz. Örnek bir requirements dosyası şu şekildedir:

base.txt

Django==1.6.2
psycopg2==2.5.2
djangorestframework==2.3.7

dev.txt

django-debug-toolbar==1.0.1

Requirements dosyalarını kullanarak uygulamaları kurmak için de:

pip install -r requirements/dev.txt

komutunu çalıştırmanız yeterlidir.

URL Konfigürasyon Dosyaları

Alt uygulamalarla ilgili url eşleştirmelerini mümkün olduğu kadar uygulamanın altındaki url.py dosyasında tutmaya çalışmalıyız. Bunu yapabilmek için ana url.py dosyasında hangi durumlarda uygulamanın url konfigürasyonunun çalışacağını belirtmemiz gerekiyor.

Örneğin:

ebergi-site/urls.py

urlpatterns += patterns('',
url(r'^dergi/', include(dergi.urls')),
)

apps/dergi/urls.py

urlpatterns += patterns('',
url(r'^yazi/$', dergi.views.yazi, name='yazi-link'),
)

Bu durumda http://localhost/dergi/yazi adresine gittiğimizde dergi uygulamamızın altındaki views.py dosyasındaki yazi() fonksiyonu çalışacak.

Ayrıca eklediğimiz her url eşleşmesi için bir name verip template’lardaki linklerde bu name’leri kullanmak değişiklikleri yönetmemizi kolaylaştıracaktır. Örneğin yazi-link ismindeki url bir gün değişirse ve template içinde gerçek url (/dergi/yazi/) ile link vermek yerine ismini (yazi-link) kullandıysak urls.py dosyasını değiştirmemiz yeterli olacaktır. Fakat template’larda gerçek url’i kullandıysak herhangi bir değişiklikte bu url’in kullanıldığı tüm template’larda değişiklik yapmamız gerekecektir.

REST API Geliştirme

Django’da REST API geliştirmek için yazılmış çok güzel bir uygulama mevcut. django rest framework (django-rest-framework.org) bu tür bir projeye başlamadan önce kesinlikle incelenmesi gereken uygulamalardan.

Django ile direk ilgisi olmasa da bir REST API geliştirirken dikkat edilmesi gereken birkaç şeye değinmek istiyorum.

Hangi durumlarda hangi HTTP yöntemleri kullanılmalı?

  • Bir veri oluşturan (kaydeden) API istekleri için POST
  • Bir veriyi okuyan API istekleri için GET
  • Bir veriyi güncelleyen API istekleri için PUT
  • Bir veriyi silen API istekleri için DELETE

Hangi durumda hangi HTTP durum kodları dönülmeli?

  • GET veya PUT ile bir veri dönüldüyse 200 OK
  • POST ile bir veri oluşturulduysa 201 Created
  • DELETE ile bir veri silindiyse 204 No Content
  • POST, PUT, DELETE gibi verilerde değişiklik yapan isteklerdeki hatalar için 400 Bad Request (form’da eksik bırakılan alanlar gibi durumlarda)

Diğer

Django’da kullanabileceğimiz birçok özellik olduğu için bir o kadar da anlatılacak yöntem bulunuyor. Bu kadar özelliği en iyi nasıl kullanacağımızı sadece bir yazıda anlatmamız ne yazık ki mümkün değil. Bu konuda yazılmış birçok kitap ve internette çok sayıda İngilizce kaynak mevcut. Belki ilerleyen sayılarımızda bu yazının devamı niteliğinde birkaç yazıyla geride kalan Django özelliklerini en etkili nasıl kullanabileceğimizi anlatabiliriz. Şimdilik genel olarak birkaç şeye daha değinmek istiyorum.

  • Eğer iyi bir sebebiniz yoksa Django’daki kullanıcı sistemi kullanılmalı. Fazladan kaydetmek istediğiniz bilgiler için ayrı bir tablo tutup her kullanıcı için bir adet profil bilgisi tutabilirsiniz. Veya Django’nun sağladığı AbstractUserBase gibi modellerinden yeni bir kullanıcı modeli türeterek kendi kullanıcı modelinizi oluşturabilirsiniz.
  • Yine eğer iyi bir sebebiniz yoksa açık bir şekilde SQL queryleri yazılmamalı, onun yerine Django’nun ORM’inin sağladığı imkanlardan faydalanılmalı. Aksi takdirde sitenizde SQL injection açıklarına sebep olabilirsiniz.
  • Sitedeki tüm formlar için Django formları kullanılmalı
  • Geliştirme ortamında virtualenv kullanılmalı ve bağımlı olunan uygulamalar pip ile kurulmalı
  • Uygulamalar küçük olmalı, bir uygulamadaki model sayısı yaklaşık 5 ile 10 arasında olmalı. Böylece her uygulamanın amacı net bir şekilde anlaşılabilmeli ve sadece amacıyla ilgili işler yapmalı.
  • Sık kullandığınız veritabanı fonksiyonları için modellere özel manager’lar yazılmalı. Böylece her seferinde aynı query’i oluşturmaktan kurtulabiliriz.