Django öğrenim serüveninizin 10. gününe hoş geldiniz! Bu kritik aşamada, temel bilgilerinizi sağlamlaştırarak daha karmaşık veritabanı ilişkilerini, güçlü RESTful API’ler geliştirmeyi ve güvenlik önlemlerini nasıl uygulayacağınızı adım adım keşfedeceğiz. Artık sadece web sayfaları tasarlamakla kalmayacak, aynı zamanda uygulamalarınızı veri odaklı ve etkileşimli hale getireceksiniz.
Django yolculuğunuzda 10. güne ulaşmak, basit CRUD (Oluşturma, Okuma, Güncelleme, Silme) operasyonlarının ötesine geçmeye hazır olduğunuz anlamına gelir. İlk günlerinizde modelleri, görünümleri ve şablonları anlamakla meşgulken, bu aşama sizi gerçek dünya uygulamalarının karmaşıklığına hazırlar. Bir düşünün: bugüne kadar bir blog veya basit bir görev listesi uygulaması yapmış olabilirsiniz. Ancak büyük ölçekli bir e-ticaret sitesi, bir sosyal medya platformu veya bir bankacılık uygulaması geliştirmek istediğinizde, sadece temel yapılar yeterli gelmez. İşte tam da bu noktada, ileri seviye veritabanı yönetimi, dış sistemlerle entegrasyon için API’ler, kullanıcı kimlik doğrulama mekanizmaları ve performans optimizasyonları devreye girer.
Bu aşama, uygulamanızın sadece çalışmasını değil, aynı zamanda güvenli, ölçeklenebilir ve yönetilebilir olmasını sağlar. Veri tutarlılığı, kullanıcı deneyimi ve arka uç işlemlerinin sorunsuz akışı, 10. gün konularının merkezindedir. Örneğin, bir kullanıcının birden fazla ürünü sepetine ekleyebilmesi, sipariş verebilmesi ve ödeme yapabilmesi için karmaşık veritabanı ilişkilerini doğru bir şekilde modellemeniz gerekir. Ayrıca, bu işlemlerin mobil uygulamalar, JavaScript tabanlı ön uçlar veya diğer harici servisler tarafından erişilebilir olması gerektiğinde, sağlam bir API altyapısına ihtiyaç duyarsınız. Bu bağlamda, bu aşamadaki öğrenimleriniz, sizi sadece bir Django geliştiricisinden, tam teşekküllü bir web uygulama mimarı olmaya doğru bir adım daha yaklaştıracaktır. Unutmayın, sağlam temeller üzerine inşa edilen bir yapı, uzun ömürlü ve başarılı olacaktır. Bu nedenle, bugünkü konulara odaklanarak, gelecekteki projeleriniz için kendinize büyük bir avantaj sağlayacaksınız.
Bu günkü konumuz, Django’nun sadece bir web çatısı olmaktan öte, tam teşekküllü bir uygulama geliştirme platformu olarak nasıl kullanılabileceğini gösterecek. İçeriklerimiz, özellikle yeni başlayanların kafasını karıştırabilecek karmaşık konuları anlaşılır bir dille açıklayarak, sizi adım adım ileri seviye uygulamalar geliştirmeye yönlendirecek. Böylece, sadece teorik bilgiyi değil, aynı zamanda pratik uygulama becerilerini de kazanmış olacaksınız. Hazırsanız, Django’nun derinliklerine doğru yelken açalım!
Django’da Gelişmiş Model Kullanımı ve Veritabanı İlişkileri Nelerdir?
Django’nun kalbi, ORM (Object-Relational Mapper) ile veritabanı etkileşimlerinde yatar. 10. günde, temel ForeignKey kullanımlarının ötesine geçerek daha karmaşık veritabanı ilişkilerini ve model özelliklerini inceleyeceğiz. Özellikle, birçok-çok (Many-to-Many) ve bire-bir (One-to-One) ilişkiler, gerçek dünya uygulamalarında sıkça karşımıza çıkar ve bu ilişkileri doğru bir şekilde modellemek, veri tutarlılığı ve sorgu verimliliği açısından kritik öneme sahiptir. Örneğin, bir e-ticaret uygulamasında bir ürünün birden fazla kategoriye ait olabilmesi veya bir kullanıcının sadece tek bir profil bilgisine sahip olması gibi senaryoları ele alalım.
Many-to-Many İlişkiler Nasıl Kurulur?
ManyToManyField iki model arasında birden fazla kaydın birbirleriyle ilişkili olabileceği durumlar için idealdir. Örneğin, bir “Kitap” modelinin birden fazla “Yazar” modeline, bir “Yazar” modelinin de birden fazla “Kitap” modeline sahip olabileceği bir kütüphane sistemi düşünün. Bu ilişkiyi kurmak için, ManyToManyField alanını modellerden birine eklemeniz yeterlidir. Django, bu iki model arasındaki ilişkiyi yönetmek için otomatik olarak üçüncü bir ara tablo (joining table) oluşturur.
# models.py
from django.db import models
class Yazar(models.Model):
ad = models.CharField(max_length=100)
soyad = models.CharField(max_length=100)
def __str__(self):
return f"{self.ad} {self.soyad}"
class Kitap(models.Model):
baslik = models.CharField(max_length=200)
yazarlar = models.ManyToManyField(Yazar, related_name='kitaplar') # related_name: tersten erişim için
yayin_tarihi = models.DateField()
def __str__(self):
return self.baslik
Yukarıdaki örnekte, bir Kitap nesnesinden kitap.yazarlar.all() ile yazarlarına, bir Yazar nesnesinden ise yazar.kitaplar.all() ile kitaplarına erişebilirsiniz. Bu esneklik, karmaşık veri yapılarını yönetmek için çok önemlidir.
One-to-One İlişkiler ve Uzantılar
OneToOneField bir modelin diğer bir modelle birebir ilişki kurmasını sağlar. Bu genellikle, User modeli gibi mevcut bir modele ek özellikler eklemek istediğinizde kullanılır. Örneğin, her kullanıcının kendine özel bir profil sayfası olmasını istiyorsanız, User modeline doğrudan alanlar eklemek yerine bir UserProfile modeli oluşturup User ile OneToOneField üzerinden ilişkilendirmek daha iyi bir yaklaşımdır.
# models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
dogum_tarihi = models.DateField(null=True, blank=True)
profil_resmi = models.ImageField(upload_to='profil_resimleri/', null=True, blank=True)
biyografi = models.TextField(blank=True)
def __str__(self):
return self.user.username
Burada on_delete=models.CASCADE parametresi, ilişkili User silindiğinde UserProfile nesnesinin de silinmesini sağlar. Bu, veri tutarlılığını korumak için hayati bir detaydır. Ayrıca, OneToOneField kullanarak temel User modelini genişletmek, Django'nun kullanıcı yönetimini bozmadan esneklik sağlar.
Gelişmiş QuerySet Metotları
QuerySet'ler üzerinde annotate(), aggregate() gibi metotları kullanarak veritabanı seviyesinde karmaşık sorgular çalıştırabilirsiniz. annotate() her nesneye yeni bir alan eklerken, aggregate() bir QuerySet'in tamamı üzerinde tek bir değer döndürür (örneğin toplam, ortalama).
# Örnek: Her yazarın kaç kitabı olduğunu bulma
from django.db.models import Count
yazarlar_kitap_sayisi = Yazar.objects.annotate(kitap_sayisi=Count('kitaplar'))
for yazar in yazarlar_kitap_sayisi:
print(f"{yazar.ad} {yazar.soyad}: {yazar.kitap_sayisi} kitap")
# Örnek: Toplam kitap sayısı
toplam_kitap_sayisi = Kitap.objects.aggregate(toplam=Count('id'))['toplam']
print(f"Veritabanındaki toplam kitap sayısı: {toplam_kitap_sayisi}")
Bu tür gelişmiş sorgular, raporlama, istatistik çıkarma ve veri analizi gibi durumlarda oldukça işinize yarayacaktır. Model ilişkilerini ve QuerySet'leri derinlemesine anlamak, performanslı ve güçlü Django uygulamaları geliştirmenin temelini oluşturur.
RESTful API'ler ile Django Uygulamalarınızı Nasıl Genişletirsiniz?
Modern web uygulamaları, genellikle farklı platformlardan (web tarayıcıları, mobil uygulamalar, masaüstü uygulamaları) erişilebilen bir arka uç servisi gerektirir. İşte bu noktada RESTful API'ler devreye girer. REST (Representational State Transfer) mimarisi, web servisleri oluşturmak için kullanılan popüler bir yaklaşımdır. Django'yu güçlü bir API sunucusuna dönüştürmenin en etkili yolu ise Django REST Framework (DRF) kullanmaktır. DRF, Django projelerinizde hızla API'ler geliştirmenizi sağlayan esnek ve kapsamlı bir araç setidir. Bu bölümde, DRF ile nasıl API oluşturulacağını adım adım öğreneceğiz.
Django REST Framework (DRF) Kurulumu ve Temelleri
DRF'yi projenize entegre etmek oldukça basittir. İlk olarak, DRF paketini kurmanız gerekir:
pip install djangorestframework
Ardından, Django projenizin settings.py dosyasına rest_framework uygulamasını ekleyin:
# settings.py
INSTALLED_APPS = [
# ...
'rest_framework',
# ... sizin uygulamalarınız
]
Serializers: Veriyi JSON'a Dönüştürme
DRF'nin temelini Serializer'lar oluşturur. Serializer'lar, Django modellerini JSON (veya XML gibi diğer formatlar) gibi dönüştürülebilir formatlara çevirmenin ve gelen veriyi model nesnelerine geri dönüştürmenin anahtarıdır. ModelSerializer ise, belirli bir model için otomatik olarak alanları ve doğrulama kurallarını oluşturan pratik bir seçenektir.
# kutuphane/serializers.py (varsayalım ki kutuphane adında bir uygulamanız var)
from rest_framework import serializers
from .models import Kitap, Yazar
class YazarSerializer(serializers.ModelSerializer):
class Meta:
model = Yazar
fields = ['id', 'ad', 'soyad']
class KitapSerializer(serializers.ModelSerializer):
yazarlar = YazarSerializer(many=True, read_only=True) # İlişkili modeli de göster
class Meta:
model = Kitap
fields = ['id', 'baslik', 'yazarlar', 'yayin_tarihi']
Burada, KitapSerializer içinde yazarlar alanını YazarSerializer kullanarak gösteriyoruz. many=True bir kitabın birden fazla yazarı olabileceğini, read_only=True ise bu alanın sadece okunabilir olduğunu (yani API üzerinden yazar eklenip silinemeyeceğini, sadece Kitap'a atanan yazarları göstereceğini) belirtir.
ViewSets ve URL Yönlendirmesi
ViewSets, DRF'de CRUD operasyonlarını (Liste, Oluşturma, Getirme, Güncelleme, Silme) tek bir sınıf altında gruplamanın güçlü bir yoludur. Django'nun urls.py dosyasında Router kullanarak ViewSet'leri otomatik olarak URL'lere bağlayabiliriz.
# kutuphane/views.py
from rest_framework import viewsets
from .serializers import KitapSerializer, YazarSerializer
from .models import Kitap, Yazar
class KitapViewSet(viewsets.ModelViewSet):
queryset = Kitap.objects.all()
serializer_class = KitapSerializer
class YazarViewSet(viewsets.ModelViewSet):
queryset = Yazar.objects.all()
serializer_class = YazarSerializer
# projenizin urls.py (örn: myproject/urls.py)
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from kutuphane.views import KitapViewSet, YazarViewSet
router = DefaultRouter()
router.register(r'kitaplar', KitapViewSet)
router.register(r'yazarlar', YazarViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(router.urls)), # API endpoint'lerini buraya dahil ediyoruz
]
Bu yapı sayesinde, /api/kitaplar/ adresine GET isteği gönderdiğinizde tüm kitapların listesini, POST isteği gönderdiğinizde yeni bir kitap oluşturabilir, /api/kitaplar/{id}/ adresine GET, PUT, DELETE istekleri göndererek belirli bir kitabı yönetebilirsiniz. DRF'nin sağladığı otomatik API tarayıcısı arayüzü sayesinde, geliştirme sürecinizde API'lerinizi kolayca test edebilirsiniz. Bu, API geliştirme sürecini inanılmaz derecede hızlandırır ve hataları ayıklamayı basitleştirir.
API Kimlik Doğrulama ve İzinler: Güvenliği Nasıl Sağlarsınız?
Her güçlü API'nin ardında sağlam bir güvenlik katmanı olmalıdır. Django REST Framework, API'lerinizi yetkisiz erişime karşı korumak için esnek kimlik doğrulama (Authentication) ve izin (Permission) mekanizmaları sunar. Kimlik doğrulama, bir kullanıcının kim olduğunu belirlerken, izinler ise bu kullanıcının belirli bir kaynağa erişip erişemeyeceğini veya belirli bir işlemi yapıp yapamayacağını kontrol eder. Bu iki kavramı doğru uygulamak, API güvenliğinizin temelini oluşturur.
Kimlik Doğrulama Yöntemleri
DRF çeşitli kimlik doğrulama yöntemlerini destekler. En yaygın kullanılanlar şunlardır:
- SessionAuthentication: Django'nun oturum tabanlı kimlik doğrulama sistemini kullanır. Tarayıcı tabanlı istemciler için idealdir. Kullanıcı giriş yaptığında bir oturum çerezi oluşturulur.
- TokenAuthentication: Her kullanıcıya benzersiz bir belirteç (token) atanır. İstemci, her API isteğinde bu belirteci HTTP başlığına ekler. Mobil uygulamalar ve JavaScript tabanlı ön uçlar için çok uygundur.
- JWT (JSON Web Token) Authentication: Daha modern ve popüler bir yöntemdir. Tokenlar şifrelenir ve kullanıcı bilgileri içerebilir. Durumsuz (stateless) bir yapı sunar, bu da ölçeklenebilirlik açısından avantajlıdır.
Bu makalede, kurulumu ve kullanımı nispeten daha basit olan TokenAuthentication'a odaklanacağız.
Token Kimlik Doğrulamayı Uygulama
İlk olarak, DRF'nin token uygulamasını INSTALLED_APPS'a eklemeniz ve veritabanı migration'larını çalıştırmanız gerekir:
# settings.py
INSTALLED_APPS = [
# ...
'rest_framework',
'rest_framework.authtoken', # Bu satırı ekleyin
# ...
]
python manage.py migrate
Ardından, kullanıcılara token atamak için bir yol sağlamalısınız. Kullanıcı oluşturulduğunda otomatik olarak token oluşturmak veya özel bir API ucu sağlamak mümkündür.
# myproject/urls.py (veya ilgili uygulamanızın urls.py'si)
from rest_framework.authtoken.views import obtain_auth_token
urlpatterns = [
# ... diğer URL'ler
path('api/token/', obtain_auth_token, name='api_token_auth'), # Kullanıcı adı ve şifre ile token alır
]
Şimdi API'lerinize bu kimlik doğrulama yöntemini uygulayabilirsiniz.
# kütüphane/views.py (KitapViewSet örneğini genişletelim)
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.authentication import TokenAuthentication
class KitapViewSet(viewsets.ModelViewSet):
queryset = Kitap.objects.all()
serializer_class = KitapSerializer
authentication_classes = [TokenAuthentication] # Token kimlik doğrulamasını etkinleştir
permission_classes = [IsAuthenticated] # Sadece kimliği doğrulanmış kullanıcılar erişebilir
Bu sayede, KitapViewSet'e erişmek isteyen her istemci, isteğin HTTP başlığına bir token eklemek zorunda kalır: Authorization: Token .
İzin Mekanizmaları
Kimlik doğrulama, kullanıcının kimliğini kanıtlar, ancak bir kaynağa erişim yetkisini belirlemez. İşte burada izinler devreye girer. DRF, kullanıma hazır izin sınıfları sunar:
- AllowAny: Herkese erişim izni verir (varsayılan).
- IsAuthenticated: Sadece kimliği doğrulanmış kullanıcılara izin verir.
- IsAdminUser: Sadece yönetici (admin) kullanıcılarına izin verir.
- IsAuthenticatedOrReadOnly: Kimliği doğrulanmış kullanıcılara tam erişim, diğerlerine sadece okuma izni verir.
Kendi özel izinlerinizi de oluşturabilirsiniz. Örneğin, sadece belirli bir grup üyesi olan veya bir nesnenin sahibi olan kullanıcılara izin vermek isteyebilirsiniz.
# kütüphane/permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Sadece nesnenin sahibi olan kullanıcılara düzenleme izni verir.
Diğer kullanıcılara okuma izni verir.
"""
def has_object_permission(self, request, view, obj):
# Okuma izinleri her zaman herkese verilir.
if request.method in permissions.SAFE_METHODS:
return True
# Yazma izinleri sadece nesnenin sahibi olan kullanıcılara verilir.
return obj.owner == request.user # Varsayalım ki modelde bir 'owner' alanı var
Ardından, bu özel izni ViewSet'inizde kullanabilirsiniz:
# kütüphane/views.py
from .permissions import IsOwnerOrReadOnly
class KitapViewSet(viewsets.ModelViewSet):
# ...
permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] # Hem kimlik doğrulama hem de sahiplik kontrolü
Bu detaylı güvenlik katmanları, API'lerinizi güçlü ve yönetilebilir kılarken, kullanıcı verilerinin ve sisteminizin korunmasını sağlar. Doğru kimlik doğrulama ve izin politikaları belirlemek, başarılı bir API stratejisinin ayrılmaz bir parçasıdır.
Asenkron Görev Yönetimi ve Arka Plan İşlemleri Neden Önemli?
Web uygulamaları, kullanıcıya anında geri bildirim vermesi beklenen interaktif arayüzlerden ibaret değildir. Genellikle, e-posta gönderimi, resim işleme, rapor oluşturma, veri analizi veya üçüncü taraf API'lerle entegrasyon gibi zaman alıcı veya yoğun işlem gerektiren görevlerle karşılaşırız. Bu tür görevleri doğrudan bir web isteği sırasında işlemek, kullanıcının isteğinin uzun süre beklemesine, hatta zaman aşımına uğramasına neden olabilir. İşte bu noktada asenkron görev yönetimi ve arka plan işlemleri hayati önem taşır. Bu, uygulamanızın performansını ve kullanıcı deneyimini önemli ölçüde artırır.
Senkron ve Asenkron İşlemler Arasındaki Fark
- Senkron İşlem: Bir görev tamamlanmadan diğerine geçilemez. Bir web isteği geldiğinde, Django bu isteği işlerken zaman alan bir operasyonla karşılaşırsa (örneğin 10 saniye süren bir e-posta gönderimi), kullanıcı bu 10 saniye boyunca beklemek zorunda kalır ve arayüz kilitlenir.
- Asenkron İşlem: Bir görev başlatıldıktan sonra, uygulama diğer işlemlere devam edebilir. Zaman alan görev ayrı bir süreçte arka planda yürütülür ve tamamlandığında sonuçlar kaydedilebilir veya kullanıcıya bildirim gönderilebilir. Bu, kullanıcı arayüzünün akıcı kalmasını ve uygulamanın daha duyarlı olmasını sağlar.
Celery ile Asenkron Görev Yönetimi
Django projelerinde asenkron görevleri yönetmek için en popüler ve güçlü araçlardan biri Celery'dir. Celery, dağıtılmış görev kuyrukları için bir sistemdir ve gerçek zamanlı işleme ile düzenli aralıklarla çalışan görevleri (cron işleri gibi) destekler. Celery'yi kullanabilmek için bir mesaj aracısına (broker) ihtiyacınız vardır; Redis veya RabbitMQ en yaygın tercihlerdir.
Celery Kurulumu ve Temel Kullanım
İlk adım olarak Celery paketini kurun:
pip install celery redis # veya pip install celery rabbitmq
Ardından, Django projenizin kök dizininde (manage.py ile aynı seviyede) bir celery.py dosyası oluşturmanız ve uygulamanızı yapılandırmanız gerekir:
# myproject/celery.py
import os
from celery import Celery
# Django ayarlarını Celery için yapılandır
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
app = Celery('myproject')
# Uygulamalardaki görevleri otomatik olarak keşfeder
app.config_from_object('django.conf:settings', namespace='CELERY')
# Yüklü tüm Django uygulamalarındaki görevleri otomatik olarak yükle
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
print(f'Request: {self.request!r}')
myproject/settings.py dosyanıza broker URL'ini ekleyin:
# myproject/settings.py
# ...
CELERY_BROKER_URL = 'redis://localhost:6379/0' # Veya RabbitMQ için 'amqp://localhost'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' # Sonuçları depolamak için
# ...
Son olarak, Django projenizin myproject/__init__.py dosyasına Celery uygulamanızı yükleyin:
# myproject/__init__.py
from .celery import app as celery_app
__all__ = ('celery_app',)
Görev Tanımlama ve Çalıştırma
Şimdi bir Django uygulamanızda (örneğin kutuphane/tasks.py) basit bir asenkron görev tanımlayalım:
# kutuphane/tasks.py
from celery import shared_task
import time
@shared_task
def send_welcome_email(user_email):
"""
Yeni kayıt olan kullanıcıya hoş geldiniz e-postası gönderir.
Zaman alan bir işlem simülasyonu.
"""
time.sleep(5) # 5 saniye bekleyerek e-posta gönderimini simüle et
print(f"Hoş geldiniz e-postası {user_email} adresine gönderildi.")
return True
Bu görevi bir Django görünümünden veya model sinyalinden çağırabilirsiniz:
# kutuphane/views.py
from django.shortcuts import render
from django.http import HttpResponse
from .tasks import send_welcome_email
def register_user(request):
# ... kullanıcı kayıt işlemleri ...
user_email = "test@example.com" # Kayıt olan kullanıcının e-postası
send_welcome_email.delay(user_email) # Görevi arka plana gönder
return HttpResponse("Kullanıcı kaydı başarıyla tamamlandı, e-posta gönderiliyor...")
.delay() metodu, görevi Celery kuyruğuna gönderir ve işleyici (worker) müsait olduğunda bu görevi arka planda işler. Bu esnada, web sunucusu hemen bir yanıt döndürerek kullanıcının beklemesini engeller.
Celery işleyiciyi ve mesaj aracısını çalıştırmak için terminalde şu komutları kullanmanız gerekir (ayrı terminallerde):
# Redis sunucusunu başlatın (eğer kullanıyorsanız)
redis-server
# Celery işleyiciyi başlatın (proje dizininizde)
celery -A myproject worker -l info
Asenkron görevler, özellikle yüksek trafikli uygulamalar ve karmaşık iş mantığına sahip sistemler için vazgeçilmezdir. Uygulamanızın daha hızlı, daha duyarlı ve daha ölçeklenebilir olmasını sağlayarak hem kullanıcı deneyimini hem de sistem performansını iyileştirir.
Vaka Analizi: Bir E-Ticaret Sepeti ve Ödeme Sistemi Nasıl Tasarlanır?
Şimdiye kadar öğrendiklerimizi birleştirerek, gerçek dünya senaryolarından birini, yani temel bir e-ticaret sepeti ve ödeme sistemi tasarımını inceleyelim. Bu vaka analizi, Django modellerinin, ilişkilerinin, DRF API'lerinin ve arka plan görevlerinin nasıl bir araya gelerek işlevsel bir sistem oluşturduğunu gösterecek.
Modeller ve İlişkiler
Bir e-ticaret sisteminde olmazsa olmaz bazı modeller ve bu modeller arasındaki ilişkiler şunlardır:
-
Ürün (Product):
name,description,price,stock. -
Kategori (Category):
name,description. (ProductileMany-to-Manyilişki, bir ürün birden fazla kategoriye ait olabilir.) -
Sepet (Cart): Her kullanıcının bir sepeti olmalı. (
UserileOne-to-Oneilişki).created_at,updated_at. -
Sepet Öğesi (CartItem): Sepetteki her ürün bir
CartItemolarak temsil edilir.cart(ForeignKeytoCart),product(ForeignKeytoProduct),quantity. -
Sipariş (Order): Kullanıcı sepetini onayladığında oluşur.
user(ForeignKeytoUser),total_price,status(pending, completed, cancelled),created_at. -
Sipariş Öğesi (OrderItem): Sipariş içindeki her ürün.
order(ForeignKeytoOrder),product(ForeignKeytoProduct),quantity,unit_price.
Bu modeller ve ilişkiler, sistemin veritabanı yapısını oluşturur. Özellikle CartItem ve OrderItem modelleri, bir Many-to-Many ilişkiye ek özellikler (adet, birim fiyat) eklemek için bir ara model (through model) görevi görür.
# e_commerce/models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.IntegerField(default=0)
categories = models.ManyToManyField(Category, related_name='products')
def __str__(self):
return self.name
class Cart(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.user.username}'s Cart"
class CartItem(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name='items')
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
class Meta:
unique_together = ('cart', 'product') # Bir sepette aynı üründen sadece bir tane olabilir (adet güncellenir)
def __str__(self):
return f"{self.quantity} x {self.product.name} in {self.cart.user.username}'s Cart"
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
total_price = models.DecimalField(max_digits=10, decimal_places=2, default=0.00)
status = models.CharField(max_length=20, default='pending') # completed, cancelled
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"Order {self.id} by {self.user.username}"
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items')
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
unit_price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return f"{self.quantity} x {self.product.name} in Order {self.order.id}"
API Entegrasyonu (DRF)
Bu modellere dayanarak DRF ile API'ler oluşturabiliriz.
- Ürün API'si: Tüm ürünleri listeleme, belirli bir ürünü detaylandırma.
-
Sepet API'si: Kullanıcının sepetini görme, sepete ürün ekleme/çıkarma, ürün adetini güncelleme. Bu API'ler
IsAuthenticatediznine sahip olmalı ve sadece kullanıcının kendi sepeti üzerinde işlem yapmasına izin vermelidir. - Sipariş API'si: Yeni sipariş oluşturma (sepeti siparişe dönüştürme), kullanıcının geçmiş siparişlerini görme. Sipariş oluşturma işlemi, veritabanı işlemlerini (stok güncelleme, sipariş öğeleri oluşturma) kapsayacağı için bir işlem (transaction) içinde yapılmalıdır.
# e_commerce/serializers.py
from rest_framework import serializers
from .models import Product, Category, Cart, CartItem, Order, OrderItem
from django.contrib.auth.models import User
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class CartItemSerializer(serializers.ModelSerializer):
product = ProductSerializer(read_only=True) # Ürün detaylarını da göster
class Meta:
model = CartItem
fields = ['id', 'product', 'quantity']
class CartSerializer(serializers.ModelSerializer):
items = CartItemSerializer(many=True, read_only=True)
# Sepet toplam fiyatını dinamik olarak hesaplayabiliriz
total_price = serializers.SerializerMethodField()
class Meta:
model = Cart
fields = ['id', 'user', 'items', 'total_price', 'created_at', 'updated_at']
read_only_fields = ['user']
def get_total_price(self, obj):
return sum(item.product.price * item.quantity for item in obj.items.all())
# e_commerce/views.py (Örnek bir sepet görünümü)
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from .models import Cart, CartItem, Product
from .serializers import CartSerializer, CartItemSerializer
class CartViewSet(viewsets.ModelViewSet):
serializer_class = CartSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
# Sadece mevcut kullanıcının sepetini döndür
return Cart.objects.filter(user=self.request.user)
def perform_create(self, serializer):
# Yeni sepet oluşturulduğunda kullanıcıyı atayın
serializer.save(user=self.request.user)
@action(detail=False, methods=['post'], url_path='add-item')
def add_item(self, request):
product_id = request.data.get('product_id')
quantity = request.data.get('quantity', 1)
try:
product = Product.objects.get(id=product_id)
cart, created = Cart.objects.get_or_create(user=request.user) # Kullanıcının sepeti yoksa oluştur
cart_item, item_created = CartItem.objects.get_or_create(cart=cart, product=product,
defaults={'quantity': quantity})
if not item_created:
cart_item.quantity += int(quantity)
cart_item.save()
return Response(CartSerializer(cart).data, status=status.HTTP_200_OK)
except Product.DoesNotExist:
return Response({'error': 'Ürün bulunamadı.'}, status=status.HTTP_404_NOT_FOUND)
except Exception as e:
return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)
# Benzer şekilde 'remove-item', 'update-item-quantity' gibi action'lar eklenebilir.
Arka Plan İşlemleri (Celery)
Ödeme tamamlandıktan sonra, kullanıcıya bir sipariş onayı e-postası göndermek veya envanterde değişiklik yapmak gibi işlemler arka planda Celery ile yürütülebilir. Bu, ödeme sürecinin hızlı kalmasını sağlar.
# e_commerce/tasks.py
from celery import shared_task
import time
@shared_task
def send_order_confirmation_email(order_id, user_email):
# Sipariş detaylarını al
# order = Order.objects.get(id=order_id)
time.sleep(10) # E-posta gönderimini simüle et
print(f"Sipariş {order_id} için onay e-postası {user_email} adresine gönderildi.")
@shared_task
def update_product_stock(product_id, quantity_ordered):
# Ürün stoklarını güncelle
# product = Product.objects.get(id=product_id)
# product.stock -= quantity_ordered
# product.save()
print(f"Ürün {product_id} için stok güncellendi. {quantity_ordered} adet düşüldü.")
Bu vaka analizi, "Day 10 Django Learning" kapsamında ele aldığımız birçok konunun (gelişmiş modeller, DRF, kimlik doğrulama, arka plan görevleri) gerçek bir projede nasıl bir araya getirilebileceğini göstermektedir. Bu şekilde bir sistem tasarlamak, sadece fonksiyonel olmakla kalmaz, aynı zamanda ölçeklenebilir, bakımı kolay ve performanslı bir uygulama oluşturmanızı sağlar.
Django Şablonları için Mobil Uyumluluk: Media Query Örnekleri
Django temel olarak bir arka uç çatısı olsa da, oluşturduğunuz web sitelerinin kullanıcılar tarafından farklı cihazlarda düzgün görüntülenmesi kritik öneme sahiptir. Bu, özellikle modern web geliştirme dünyasında mobil cihazların yaygınlaşmasıyla daha da belirgin hale gelmiştir. Django'nun kendisi doğrudan mobil uyumluluk sağlamaz, ancak statik dosyaları (CSS, JavaScript, resimler) yönetme şekli, duyarlı (responsive) tasarımları kolayca uygulamanıza olanak tanır. Django şablonlarını kullanarak HTML çıktısı üretirken, bu HTML çıktısına bağlı CSS dosyalarınız aracılığıyla mobil uyumluluğu sağlayabiliriz.
Statik Dosyaların Yönetimi ve Media Queries
Django projelerinde CSS dosyalarınızı genellikle bir uygulamanın static/css dizininde veya projenin ana static dizininde barındırırsınız. Şablonlarınızda bu dosyalara {% load static %} ve {% static 'css/style.css' %} etiketleriyle erişirsiniz. Mobil uyumluluk için, CSS dosyalarınızda "media queries" kullanmanız gerekir. Media queries, ekran boyutuna, cihaza ve diğer özelliklere bağlı olarak farklı stil kuralları uygulamanıza olanak tanıyan CSS3 özellikleridir.
Temel Media Query Örneği
Diyelim ki, masaüstü görünümünde üç sütunlu bir düzeniniz var, ancak mobil cihazlarda bu sütunların dikey olarak sıralanmasını istiyorsunuz.
{% load static %}
{% block title %}Django Uygulaması{% endblock %}
İçerik 1
İçerik 2
İçerik 3
Şimdi, myapp/static/css/style.css dosyanıza aşağıdaki CSS kodunu ekleyelim:
/* Genel stil kuralları (Mobil öncelikli yaklaşım) */
.container {
display: flex;
flex-direction: column; /* Mobil cihazlarda sütunlar alt alta */
padding: 10px;
}
.column {
flex: 1; /* Mobil cihazlarda tam genişlik */
margin-bottom: 10px;
background-color: #f0f0f0;
padding: 15px;
border-radius: 5px;
}
/* Masaüstü cihazlar için media query */
@media screen and (min-width: 768px) {
.container {
flex-direction: row; /* Masaüstünde yan yana sütunlar */
justify-content: space-around;
}
.column {
flex: 1; /* Eşit genişlikte dağılım */
margin-right: 10px; /* Sütunlar arasına boşluk */
margin-bottom: 0; /* Alttaki boşluğu kaldır */
}
.column:last-child {
margin-right: 0;
}
}
/* Ekstra geniş ekranlar için başka bir örnek */
@media screen and (min-width: 1200px) {
.container {
max-width: 1140px; /* Daha büyük ekranlarda konteyneri sabitle */
margin: 0 auto; /* Ortala */
}
}
Yukarıdaki örnekte, varsayılan olarak mobil cihazlar için tasarlanmış bir düzen (flex-direction: column) tanımladık. Daha sonra min-width: 768px olan ekranlar (genellikle tabletler ve masaüstü bilgisayarlar) için flex-direction: row kullanarak sütunları yatay hale getirdik. Bu "mobil öncelikli" (mobile-first) yaklaşımdır ve modern web geliştirmenin en iyi uygulamalarından biridir.
Django, bu statik dosyaları sunmak için STATIC_URL ve STATICFILES_DIRS gibi ayarları kullanır. Geliştirme ortamında python manage.py runserver otomatik olarak bu dosyaları sunar. Üretim ortamında ise python manage.py collectstatic komutuyla tüm statik dosyalarınızı tek bir dizinde toplar ve genellikle Nginx veya Apache gibi bir web sunucusu aracılığıyla servis edersiniz.
Mobil uyumluluk sadece düzenle sınırlı değildir. Resimlerin optimize edilmesi (srcset özniteliği, picture etiketi), dokunmatik odaklı arayüz elemanları ve JavaScript ile dinamik olarak içeriğin yüklenmesi gibi konular da bu kapsamda değerlendirilmelidir. Django'nun şablon sistemi bu tür frontend geliştirmelerini doğrudan desteklemezken, HTML çıktınız üzerinde tam kontrol sağlayarak ve statik dosya yönetimini kolaylaştırarak bu entegrasyonu mümkün kılar. Bu da demek oluyor ki, Django ile geliştirme yaparken sadece arka ucu değil, aynı zamanda kullanıcıların projenizle etkileşim kuracağı ön yüz deneyimini de göz önünde bulundurmalısınız.
Django'da 10. Günü Başarıyla Tamamlamanın Ardından
Django öğrenim serüveninizin 10. gününü başarıyla tamamladınız ve bu, temel bir web geliştiricisinden daha karmaşık, güvenli ve ölçeklenebilir uygulamalar tasarlayabilen bir mimara doğru attığınız önemli bir adımdır. Bu günde, sadece teknik konulara değil, aynı zamanda gerçek dünya uygulamalarının nasıl yapılandırıldığına dair derinlemesine bir bakış açısı kazandınız. Veritabanı modellemelerindeki incelikleri, Many-to-Many ve One-to-One ilişkilerinin gücünü keşfettiniz. Django REST Framework ile API'ler oluşturmanın temellerini ve bu API'leri kimlik doğrulama ile güvenli hale getirmenin yollarını öğrendiniz. Ayrıca, uygulamanızın performansını artırmak ve kullanıcı deneyimini iyileştirmek için asenkron görevlerin ve Celery'nin nasıl kullanılabileceğini de gördünüz. Son olarak, mobil uyumlu tasarımların önemini ve Django'nun statik dosya yönetimi aracılığıyla medya sorgularının nasıl entegre edilebileceğini tartıştık.
Bu bilgiler, sizi sadece bir "Django kullanıcısı" olmaktan çıkarıp, daha bilinçli ve yetenekli bir "Django geliştiricisi" yapacaktır. Her zaman olduğu gibi, öğrenme süreci devam eder ve bu edinilen bilgiler, daha büyük ve iddialı projeler için sağlam bir temel oluşturur. Pratik yaparak, farklı senaryoları deneyerek ve yeni teknolojileri keşfederek kendinizi geliştirmeye devam etmeniz büyük önem taşımaktadır. Unutmayın, en iyi öğrenme, uygulamadır.
Sıkça Sorulan Sorular
- Django REST Framework (DRF) neden kullanılır?
- DRF, Django üzerinde RESTful API'ler geliştirmeyi son derece kolaylaştıran güçlü ve esnek bir kütüphanedir. Model tabanlı serialleştiriciler, viewset'ler, kimlik doğrulama ve izin mekanizmaları gibi özellikleriyle API geliştirme sürecini hızlandırır, kod tekrarını azaltır ve daha güvenli API'ler oluşturmanızı sağlar. Mobil uygulamalar veya JavaScript ön uçları gibi farklı istemcilerle veri alışverişi yapmak için vazgeçilmezdir.
- Many-to-Many ve One-to-One ilişkileri ne zaman kullanmalıyım?
ManyToManyField, bir modelin birçok başka modelle, o diğer modellerin de aynı şekilde ilk modelle ilişkili olabileceği durumlarda kullanılır (örneğin, bir öğrencinin birden fazla kursa kayıt olması ve bir kursa birden fazla öğrencinin kayıt olması).OneToOneFieldise iki model arasında birebir bir ilişki gerektiğinde kullanılır (örneğin, her kullanıcının yalnızca bir profil sayfasına sahip olması veya temel bir modele ek özellikler eklemek için).- Celery ne işe yarar ve ne zaman kullanmalıyım?
- Celery, Django uygulamanızın performansını artırmak için zaman alıcı veya yoğun işlem gerektiren görevleri arka planda asenkron olarak yürütmeye yarayan bir dağıtılmış görev kuyruğu sistemidir. E-posta gönderimi, resim işleme, rapor oluşturma, veri senkronizasyonu gibi işlemler için kullanılmalıdır. Bu sayede web sunucunuzun kullanıcı isteklerine daha hızlı yanıt vermesini sağlayarak kullanıcı deneyimini iyileştirirsiniz.
- API güvenliğini nasıl sağlayabilirim?
- API güvenliği için kimlik doğrulama (authentication) ve izin (permission) mekanizmalarını kullanmalısınız. DRF,
TokenAuthentication,SessionAuthentication,JWTAuthenticationgibi yöntemler sunar. İzinler iseIsAuthenticated,IsAdminUserveya kendi yazacağınız özel izin sınıfları ile belirli kaynaklara erişimi kısıtlamanıza olanak tanır. Her isteğin güvenli bir şekilde doğrulanmasını ve yetkilendirilmesini sağlamak kritik öneme sahiptir. - Mobil uyumlu bir Django sitesi nasıl yapılır?
- Django bir arka uç çatısı olduğundan, mobil uyumluluk (responsive design) genellikle frontend (ön yüz) teknikleriyle sağlanır. CSS media query'lerini kullanarak farklı ekran boyutlarına göre stil kuralları tanımlayabilirsiniz. Meta viewport etiketini HTML başlığına eklemek, mobil cihazların sayfayı doğru ölçeklendirmesi için önemlidir. Django'nun statik dosya yönetimi bu CSS ve JavaScript dosyalarını projenize kolayca entegre etmenizi sağlar.