Django best practiceler
May 19, 2018 · 3 minute read · Commentsprogrammingpython
Configler
- Django environ kullanılmalı.
- Her ortam için ayrı requirements dosyası olmalı(prod, staging, dev)
- Her ortam için ayrı settings dosyası olmalı.
Modeller
Birtane
BaseModel
yapıp, bütün modelleri bu modelden extend etmek lazım. Bu sayede butun modelleri etkileyecek bir degisiklik yapmak istedigimizde sadece olusturdugumuz base modelde degisiklik yapmamiz yeterli olacaktir. Mesela butun objelerimizin olusturulma ve en son update edilme tarihlerini tutmak istiyoruz. Bunun icin butun modellere field eklemek yerine sadece base modele gerekli fieldlari eklememiz yeterli olacaktir. Bkz: TimeStampedModelİlişkilerde herzaman
related_name
ataması yapmak lazım.Related nameler anlaşılır olmalı, olabildiğince modelin ismine yakın olmalı. Mesela
FirmInvoicePaymentRequest
modeli üzerineFirmInvoice
modeline ForeignKey ekliyorsakpayment_requests
veyadafirm_invoice_payment_requests
yapmalı. Çünkü proje büyüdükçe ortalık karışabiliyor.
Querysetler
select_related
,prefetch_related
,only
gibi performansı etkileyen şeyleri kullanmak lazım.- Annotation yaparken annotate ettiğimiz attribute’un başına
ann
gibi bir ön ek eklemek güzel olur. Bu sayede mesela templatein ıcinde objeye bakan developer{{ myobj.ann_unpaid_amount }}
gibi bir kod gördüğünde bunun obje üzerinde duran bir field olmayıp, bir annotation olduğunu anlayabilir. Ayrıca başına bir ön ek koymadığımız durumda ileride modele annotation ile aynı isimde bir field veya propery eklendiğinde hataya sebep olacaktır. Bu sayede bununda önüne geçmiş oluruz.MyModel.objects.annotate(ann_unpaid_amount=Sum(...))
gibi. - Çok fazla tabloyu joinleyen sorgulardan kaçınmalı. Herşeyi tek sorguda getireyim performanslı olsun diye düşünürken o tek sorgunun gelmesi daha uzun sürüyor olabilir. Birden fazla sorgu ile çektiğimiz kayıtları Python tarafında in_bulk ile birleştirebiliyoruz.
Viewlar
- Class based viewların nimetlerinden yararlanmak lazım.
- Class based viewlarda neler var neler yok iyice öğrenmek lazım(CBV inspector).
BaseCreateView
,BaseUpdateView
,BaseTemplateView
gibi base viewlar oluşturmak ve onları kullanmak lazım.- Viewları isimlendirirken
InvoiceUpdateView
,ProductListView
gibi isimlendirmek lazım.
Urller
- Her app için ayrı bir
urls.py
oluşturmak lazım. - Url isimleri ve linkleri olabildiğince aynı olmalı. Sadece sayfanın url’ine bakarak ilgili view’ın hangi app icerisindeki hangi view olduğunu developer tahmin edebilmeli.
Mesela şu urle bakalım: example.com/demand/invoice/update/1/
: Bu urle bakarak urlin viewina gitmek istediğimde bakmam gereken viewin demand
app’i içerisinde InvoiceUpdateView
olduğunu tahmin edebiliyorum.
Migrationlar
Custom migrationlar içerisinde olabildiğince constant, function vs kullanmaktan kaçınmak lazım. Çünkü migrationi oluşturduğumuz anda varlolan bir fonksiyon ileri bir tarihte silinmiş veya değiştirilmiş olabilir. Böyle bir durumda migrationları temiz bir DB üzerinde çalıştırıldığında migrationlar patlayabilir.
Migration içerisinde modelleri kullanacaksak, modelleri migration dosyasının en üstünde direk import etmek yerine
apps.get_model
kullanmak lazım.apps.get_model
modelin o migrationin oluşturulduğu andaki durumunu alır. Model üzerinde daha sonradan eklenen fieldları almaz. Modeller direk import edildiği durumda; proje geliştirilmeye devam ettikçe modele yeni fieldlar eklenebileceğinden yeni bir db uzerinde migrationlar çalıştırıldığında daha 1. migration’daProduct.objects.all()
gibi bir queryset varsa eğer, bu querysetProduct
modeli üzerindeki bütün fieldları çekmeye calışacağı için 2. migration’da eklenen yeni field’i da model üzerinde var zannedip çekmeye çalışacak ve patlayacaktır. Bakınız
Yanlış kullanım:
from product import Product
def forward_func(apps, schema_editor):
Product.objects.all()
Dogru kullanım:
def forward_func(apps, schema_editor):
Product = apps.get_model("product.Product")
Product.objects.all()
- Custom migrationlar herzaman bir transaction bloğu içerisinde çalıştırmalı. Aksi taktirde migration esnasında bir hata meydana gelirse data bozulacaktır.
Migrationlar hakkinda yazdigim su yazilarada bakabilirsiniz:
Formlar
- Base widget’lar oluşturup olabildigince onları kullanmak lazım. Proje büyüdüğünde bütün projede değişiklik yapmak yerine sadece base widgetlarda oynayabilirsiniz.
ModelForm
‘lardaMeta.exclude
ve__all__
yerineMeta.fields
kullanılmalı. Bu sayede formda modelin hangi fieldlarının kullandığıni görebiliyoruz. Ayrıcaexclude
ve__all__
kullandığımızda modele yeni bir field eklendiğinde otomatik olarak formda çıkmaya başlayacaktır. Bu genelde istenen bir durum olmaz.
Sinyaller
- Sinyal receiver’ların başında o sinyalin çağrıldığını loglamak lazım. Çünkü proje büyüdükçe bir event gerçekleştiğinde obje üzerinden işlem yapan sinyalleri görmüş oluruz.
- Bir model için her app içerisinde sadece bir receiver yapmak ve o receiver içerisinde duruma göre işlemi gerçekleştirecek fonksiyonları çağırmak daha iyi. Bu şekilde daha anlasilir ve debug edilebilir oluyor. Diğer türlü bütün receiverlara bakmanız gerekecektir.