Herkese merhabalar,
Bu günkü makalemin konusu biraz spesifik. Ancak bu soru vesilesi ile bir problem üzerine birden fazla yaklaşım nasıl sergilenebileceğini de görme fırsatı olduğundan bu konu hakkında bir makale yazmak istedim…
Problemin Tanımı
Diyelim ki bir web projeniz var ve o veya bu şekilde veritabanındaki field larınızdan birisinin liste halinde olması gerekiyor. Ancak varsayılan olarak listeyi veritabanında direkt tutamadığımız için alternatif bir çözüme ihtiyaç duyuyorsunuz. Nasıl çözebilirsiniz?
Çözüm 1: Listenizi Model içerisinde dönüştürüp JSON olarak Saklayarak
Eğer kullandığınız veritabanı JSON veri tipini destekliyorsa, bu çözümü uygulamak gayet kolay. Diyelim ki bir araba alım-satım şirketinin veritabanını kurguluyorsunuz ve her marka altındaki modelleri liste olarak tutmaya karar verdiniz;
from django.db import models
import json
class Brand(models.Model):
brand_name = models.CharField(max_length=200)
_car_models = models.CharField(db_column="car_models", max_length=500)
@property
def car_models(self):
return json.loads(self._car_models)
@car_models.setter
def car_models(self, x):
self._car_models = json.dumps(x)
Test edelim;
# Save
# sample_brand = Brand()
# sample_brand.brand_name = "Mercedes"
# sample_brand.car_models = ["c200", "c180", "e220d"]
# sample_brand.save()
# Get
# sample_brand = Brand()
# print(Brand.objects.get().car_models)
# expected output: ['c200', 'c180', 'e220d']
Çözüm 2: ManytoMany ilişkisi Kurarak
Daha optimize bile sayılabilecek (bu sayede kompleks sorgular yazmanıza da DB imkan tanır) çözümde liste halinde tutulması gereken kolonlarınızı farklı bir tablo oluşturarak tutmak mantıklı olabilir;
class TruckModel(models.Model):
truck_name = models.CharField(max_length=100)
def __str__(self):
return self.truck_name
class TruckBrand(models.Model):
brand_name = models.CharField(max_length=100)
truck_models = models.ManyToManyField(TruckModel)
def __str__(self):
return self.brand_name
Bu yöntemi test edelim;
# Creation ford = TruckBrand(brand_name="Ford") ford.save() truck_model_1 = TruckModel(truck_name="F150") truck_model_1.save() truck_model_2 = TruckModel(truck_name="F250") truck_model_2.save() truck_model_3 = TruckModel(truck_name="F350") truck_model_3.save() # Relation ford.truck_models.add(truck_model_1) ford.truck_models.add(truck_model_2) ford.truck_models.add(truck_model_3) ford.save() # Get print(ford.truck_models.last().truck_name) # Expected output: 'F350'
Çözüm 3: JSONField Kullanarak (Veritabanı Bağımlı)
Pek tavsiye etmeyecek olsam da bir projenin veritabanı kolay kolay değişmeyeceğinden, alternatif olarak yazmak istedim, eğer PostgreSQL kullanıyorsanız;
from django.db.models import JSONField
bu şekilde direkt olarak JSON objesi şeklinde kolon biçiminde tutmak mümkün.
Final Görüş
Çoğu zaman karşılaştığımız problemlerin birden fazla çözümü mevcut. Bu örnekte de görebileceğimiz gibi, her çözüm bizi cevaba götürüyor ama her birinin avantajları ve dezavantajları mevcut. Mesela 1. çözümü tercih edersek yeni bir tablo eklemeye gerek kalmıyor, ancak performans olarak sorgu yapmak istediğimizde başımızı ağrıtabilir. 2. çözüm birden fazla tablo üzerinde işlem yaptırdığından DB’ye yük bindiriyorken, 3. çözümde veritabanı türüne bağlı olarak işimize yaramayabiliyor.
Bir sonraki yazımda görüşmek üzere 🙂
Projenin örnek kodlarına şuradan ulaşabilirsiniz:
https://github.com/Natgho/django-orm-listfield
Kaynaklar;
https://docs.djangoproject.com/en/3.2/ref/models/fields/#django.db.models.JSONField
https://pganalyze.com/blog/postgres-jsonb-django-python
https://pypi.org/project/django-jsonfield-backport/
https://stackoverflow.com/questions/49955905/django-jsonfield-filtering-queryset
https://stackoverflow.com/questions/22340258/list-field-in-model
Hocam, emeğinize sağlık. Postgres’in Arrayfield’ını da liste tutmak için kullandığınız oluyor mu?
Selamlar Israfil,
Açıkcası hiç kullanmıyorum desem abartmış olmam. O çözümü yazmadım bile çünkü ArrayField’da senden bir aralık bekliyor, yani şematize edilmiş olması gerekiyor tablonun. Afaki bir örnek verecek olursam arabanın dört tekerleğinin özelliklerini tutmak gibi, statik uzunluktaki değerler için önerilmiş, dökümantasyonun açıklaması da bu yönde. O nedenle kullanmıyorum. Dinamik olması önemli bir avantaj.
Cevabınız içşn teşekkürler hocam.