Django’da CRUD İşlemleri ve Model İlişkileri (OneToOne, ForeignKey, ManyToMany) Uygulamalı Rehber

Django’da CRUD işlemleri (Create, Read, Update, Delete) ile birlikte ilişki türlerini (OneToOne, ForeignKey, ManyToMany) öğreten kapsamlı bir eğitim hazırlayabiliriz. Bu proje:


📚 “Okul Kulüp Yönetim Sistemi”

Bu sistemde:

  • Öğrenciler olacak

  • Öğrencilerin profili olacak

  • Öğrenciler kulüplere katılacak

Böylece:

İlişki        Django Alanı        Örnek
Bire Bir        OneToOneField            Öğrenci → Öğrenci Profili
Bire Çok        ForeignKey            Öğretmen → Öğrenciler
Çoka Çok        ManyToManyField            Öğrenci ↔ Kulüpler

Aynı zamanda CRUD işlemleri yapılacak.


Django CRUD + İlişkiler Eğitim Projesi

1️⃣ Proje Oluşturma

django-admin startproject okul
cd okul
python manage.py startapp yonetim

settings.py

INSTALLED_APPS = [
    'yonetim',
]

2️⃣ Model Tasarımı (İlişkiler)

models.py

from django.db import models

class Ogretmen(models.Model):
    ad = models.CharField(max_length=50)
    soyad = models.CharField(max_length=50)

    def __str__(self):
        return f"{self.ad} {self.soyad}"


class Ogrenci(models.Model):
    ad = models.CharField(max_length=50)
    soyad = models.CharField(max_length=50)

    ogretmen = models.ForeignKey(
        Ogretmen,
        on_delete=models.CASCADE,
        related_name="ogrenciler"
    )

    def __str__(self):
        return f"{self.ad} {self.soyad}"


class Profil(models.Model):
    ogrenci = models.OneToOneField(
        Ogrenci,
        on_delete=models.CASCADE
    )

    dogum_tarihi = models.DateField()
    sehir = models.CharField(max_length=100)

    def __str__(self):
        return f"{self.ogrenci.ad} Profil"


class Kulup(models.Model):
    ad = models.CharField(max_length=100)

    ogrenciler = models.ManyToManyField(Ogrenci)

    def __str__(self):
        return self.ad

3️⃣ İlişki Diyagramı

Ogretmen
   │
   │  (1 → N)
   ▼
Ogrenci
   │
   │ (1 → 1)
   ▼
Profil

Ogrenci
   ▲
   │ (N ↔ N)
   │
Kulup

4️⃣ Migration

python manage.py makemigrations
python manage.py migrate

5️⃣ Admin Panel

admin.py

from django.contrib import admin
from .models import Ogretmen, Ogrenci, Profil, Kulup

admin.site.register(Ogretmen)
admin.site.register(Ogrenci)
admin.site.register(Profil)
admin.site.register(Kulup)

6️⃣ CRUD İşlemleri

CREATE (Kayıt Ekleme)

views.py

from django.shortcuts import render, redirect
from .models import Ogrenci
from .forms import OgrenciForm


def ogrenci_ekle(request):

    form = OgrenciForm(request.POST or None)

    if form.is_valid():
        form.save()
        return redirect("ogrenci_list")

    return render(request,"ogrenci_ekle.html",{"form":form})

READ (Listeleme)

def ogrenci_list(request):

    ogrenciler = Ogrenci.objects.all()

    return render(request,"ogrenci_list.html",{
        "ogrenciler":ogrenciler
    })

UPDATE (Güncelleme)

def ogrenci_guncelle(request,id):

    ogrenci = Ogrenci.objects.get(id=id)

    form = OgrenciForm(
        request.POST or None,
        instance=ogrenci
    )

    if form.is_valid():
        form.save()
        return redirect("ogrenci_list")

    return render(request,"ogrenci_ekle.html",{"form":form})

DELETE (Silme)

def ogrenci_sil(request,id):

    ogrenci = Ogrenci.objects.get(id=id)
    ogrenci.delete()

    return redirect("ogrenci_list")

7️⃣ Form

forms.py

from django import forms
from .models import Ogrenci

class OgrenciForm(forms.ModelForm):

    class Meta:
        model = Ogrenci
        fields = "__all__"

8️⃣ URL Tanımları

urls.py

from django.urls import path
from . import views

urlpatterns = [

    path("ogrenciler/",views.ogrenci_list,name="ogrenci_list"),

    path("ogrenci-ekle/",views.ogrenci_ekle,name="ogrenci_ekle"),

    path("ogrenci-guncelle/<int:id>/",
         views.ogrenci_guncelle,
         name="ogrenci_guncelle"),

    path("ogrenci-sil/<int:id>/",
         views.ogrenci_sil,
         name="ogrenci_sil"),
]

9️⃣ Template (Liste)

<h1>Öğrenciler</h1>

<a href="{% url 'ogrenci_ekle' %}">Yeni Öğrenci</a>

<ul>

{% for ogrenci in ogrenciler %}

<li>

{{ ogrenci.ad }} {{ ogrenci.soyad }}

<a href="{% url 'ogrenci_guncelle' ogrenci.id %}">Düzenle</a>

<a href="{% url 'ogrenci_sil' ogrenci.id %}">Sil</a>

</li>

{% endfor %}

</ul>

ogrenci_ekle.html dosyasını da tamamlayalım. Bu sayfa öğrenci ekleme ve güncelleme (CREATE + UPDATE) işlemlerinde kullanılan form sayfasıdır.


📄 ogrenci_ekle.html

<!DOCTYPE html>
<html>
<head>
<title>Öğrenci Ekle</title>
</head>

<body>

<h1>Öğrenci Ekle</h1>

<form method="POST">

{% csrf_token %}

{{ form.as_p }}

<button type="submit">Kaydet</button>

</form>

<br>

<a href="{% url 'ogrenci_list' %}">Öğrenci Listesine Dön</a>

</body>
</html>

Kaynak Kod: https://github.com/nuritiras/okulyonetim.git


10️⃣ ManyToMany Kullanımı

Bir öğrencinin kulüplerini görmek:

ogrenci = Ogrenci.objects.get(id=1)

ogrenci.kulup_set.all()

Bir kulüpteki öğrenciler:

kulup = Kulup.objects.get(id=1)

kulup.ogrenciler.all()

11️⃣ ORM Sorgu Örnekleri

Öğretmenin öğrencileri

ogretmen = Ogretmen.objects.get(id=1)

ogretmen.ogrenciler.all()

Öğrencinin öğretmeni

ogrenci.ogretmen

Öğrencinin profili

ogrenci.profil

Öğrendiğin Django Konuları

Bu uygulamada:

✅ Model tasarımı
✅ CRUD işlemleri
✅ Django ORM
✅ OneToOneField
✅ ForeignKey
✅ ManyToManyField
✅ ModelForm
✅ Template
✅ URL routing

öğrenilmiş olur.


Ek Bilgi:

Django’da related_name, ilişkili model üzerinden ters (reverse) sorgu yapabilmemizi sağlayan isimdir.

Senin örneğindeki model şöyleydi:

class Ogrenci(models.Model):
    ad = models.CharField(max_length=50)
    soyad = models.CharField(max_length=50)

    ogretmen = models.ForeignKey(
        Ogretmen,
        on_delete=models.CASCADE,
        related_name="ogrenciler"
    )

Burada:

  • Ogrenci modeli

  • Ogretmen modeline ForeignKey ile bağlıdır

Yani ilişki:

Ogretmen (1)  ------>  (N) Ogrenci

Bir öğretmenin birden fazla öğrencisi olabilir.


1️⃣ related_name Olmadan

Eğer related_name yazmazsan Django otomatik isim üretir.

ogretmen.ogrenci_set.all()

Örnek:

ogretmen = Ogretmen.objects.get(id=1)

ogretmen.ogrenci_set.all()

Bu öğretmenin tüm öğrencilerini getirir.

Ama bu isim:

ogrenci_set

çok okunaklı değildir.


2️⃣ related_name Kullanırsak

related_name="ogrenciler"

yazarsak artık şöyle erişebiliriz:

ogretmen.ogrenciler.all()

Örnek:

ogretmen = Ogretmen.objects.get(id=1)

ogrenciler = ogretmen.ogrenciler.all()

Bu daha anlaşılır ve profesyonel bir kullanımdır.


3️⃣ Mantık Diyagramı

Ogretmen
   │
   │ ForeignKey
   ▼
Ogrenci

Normalde Django:

ogretmen.ogrenci_set

oluşturur.

Ama related_name yazarsak:

ogretmen.ogrenciler

oluşturur.


4️⃣ İki Yönlü Erişim

Öğrenciden öğretmene gitmek

ogrenci.ogretmen

Öğretmenden öğrencilere gitmek

ogretmen.ogrenciler.all()

5️⃣ Django ORM Mantığı

NeredenNereyeKod
Öğrenci → Öğretmen        FK        ogrenci.ogretmen
Öğretmen → Öğrenciler        related_name        ogretmen.ogrenciler.all()

6️⃣ Neden Çok Önemli?

Büyük projelerde related_name kullanmazsan:

comment_set
post_set
user_set

gibi karışık isimler oluşur.

Profesyonel Django projelerinde genelde:

related_name="ogrenciler"
related_name="yorumlar"
related_name="siparisler"

gibi anlamlı isimler kullanılır.


Django ORM’de ilişkilerle en çok kullanılan sorguları bilmek çok önemlidir. Özellikle ForeignKey, OneToOne ve ManyToMany ilişkilerinde performanslı sorgular yazmayı sağlar.

Aşağıda sana en önemli 15 Django ORM ilişki sorgusunu basit örneklerle hazırladım.

Örnek modeller:

class Ogretmen(models.Model):
    ad = models.CharField(max_length=50)

class Ogrenci(models.Model):
    ad = models.CharField(max_length=50)
    ogretmen = models.ForeignKey(
        Ogretmen,
        on_delete=models.CASCADE,
        related_name="ogrenciler"
    )

class Kulup(models.Model):
    ad = models.CharField(max_length=100)
    ogrenciler = models.ManyToManyField(Ogrenci)

1️⃣ Tüm kayıtları getirme

Ogrenci.objects.all()

Veritabanındaki tüm öğrencileri getirir.


2️⃣ ID ile kayıt getirme

Ogrenci.objects.get(id=1)

Tek bir kayıt döndürür.


3️⃣ Filtreleme

Ogrenci.objects.filter(ad="Ahmet")

Adı Ahmet olan öğrencileri getirir.


4️⃣ ForeignKey üzerinden filtreleme

Ogrenci.objects.filter(ogretmen__ad="Ali")

Öğretmeni Ali olan öğrencileri getirir.

Burada:

ogretmen__ad

şu anlama gelir:

Ogrenci → Ogretmen → ad

5️⃣ related_name ile erişim

ogretmen = Ogretmen.objects.get(id=1)

ogretmen.ogrenciler.all()

Bir öğretmenin tüm öğrencilerini getirir.


6️⃣ ManyToMany ilişkisi sorgulama

kulup = Kulup.objects.get(id=1)

kulup.ogrenciler.all()

Kulüpteki tüm öğrenciler.


7️⃣ Öğrencinin kulüpleri

ogrenci.kulup_set.all()

Öğrencinin katıldığı kulüpler.


8️⃣ contains arama

Ogrenci.objects.filter(ad__contains="ah")

İçinde "ah" geçen isimler


9️⃣ icontains (büyük küçük harf duyarsız)

Ogrenci.objects.filter(ad__icontains="ah")
Ahmet
AHMET
ahmet

hepsini bulur.


🔟 order_by (sıralama)

Ogrenci.objects.order_by("ad")

Ada göre sıralar.

Ters sıralama:

Ogrenci.objects.order_by("-ad")

1️⃣1️⃣ count()

Ogrenci.objects.count()

Toplam öğrenci sayısı.


1️⃣2️⃣ exists()

Ogrenci.objects.filter(ad="Ahmet").exists()

Kayıt var mı kontrol eder.


1️⃣3️⃣ select_related (performans)

ForeignKey ilişkilerinde kullanılır.

Ogrenci.objects.select_related("ogretmen")

Bu sayede:

Ogrenci → Ogretmen

tek SQL sorgusunda gelir.

Normalde:

N + 1 query problemi

oluşabilir.


1️⃣4️⃣ prefetch_related

ManyToMany ilişkilerinde kullanılır.

Kulup.objects.prefetch_related("ogrenciler")

Kulüp ve öğrencileri tek sorgu ile optimize eder.


1️⃣5️⃣ annotate (hesaplama)

Öğretmenin kaç öğrencisi var?

from django.db.models import Count

Ogretmen.objects.annotate(
    ogrenci_sayisi=Count("ogrenciler")
)

Sonuç:

Ali → 5 öğrenci
Veli → 3 öğrenci

Django ORM İlişki Mantığı Diyagramı

Ogretmen
   │
   │  ForeignKey
   ▼
Ogrenci
   ▲
   │
ManyToMany
   │
Kulup

Profesyonel Django Geliştiricilerin En Çok Kullandığı 5 ORM

ORMAmaç
filter            veri filtreleme
select_related            FK performansı
prefetch_related            ManyToMany performansı
annotate            veri hesaplama
aggregate            toplam veri


🚀 Django ORM’de En Kritik Konu

N+1 Query Problemi ve ORM Performans Optimizasyonu

Bu konu:

  • Orta seviye Django geliştiriciyi

  • Profesyonel Django geliştiriciden ayıran konudur.


Yorumlar

Bu blogdaki popüler yayınlar

Pardus Üzerine Django Kurulumu

Python ile Web Geliştirme: Django App Oluşturma