Django Model + CRUD Mini Proje
Proje Adı: 🎓 Öğrenci Kayıt Sistemi
Bu projede:
✅ Model oluşturacağız
✅ Listeleme (List)
✅ Ekleme (Create)
✅ Güncelleme (Update)
✅ Silme (Delete)
✅ Bootstrap tasarım
🏗 1️⃣ Proje Oluşturma
django-admin startproject okulproje
cd okulproje
python manage.py startapp ogrenci
⚙ 2️⃣ settings.py Ayarı
INSTALLED_APPS = [
...
'ogrenci',
]
🧠 3️⃣ Model Oluşturma
📁 ogrenci/models.py
from django.db import models
class Ogrenci(models.Model):
ad = models.CharField(max_length=50)
soyad = models.CharField(max_length=50)
yas = models.IntegerField()
numara = models.CharField(max_length=20, unique=True)
kayit_tarihi = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"{self.ad} {self.soyad}"👍 Şimdi her satırı tek tek ve sade şekilde açıklayalım:
class Ogrenci(models.Model):
🔹 class → Python’da sınıf tanımlamak için kullanılır.
🔹 Ogrenci → Modelin adı. Bu isim veritabanında tablo adı olarak kullanılır (genelde ogrenci veya app_adi_ogrenci şeklinde oluşur).
🔹 models.Model → Django’nun temel model sınıfıdır.
Yani bu satır şunu söyler:
“Ben veritabanında bir tablo oluşturacağım ve adı Ogrenci olacak.”
ad = models.CharField(max_length=50)
🔹 ad → Veritabanındaki sütunun adı.
🔹 CharField → Metin (string) alanıdır.
🔹 max_length=50 → En fazla 50 karakter olabilir.
Yani:
Öğrencinin adı en fazla 50 karakter olabilir.
soyad = models.CharField(max_length=50)
🔹 Öğrencinin soyadı alanı.
🔹 En fazla 50 karakter olabilir.
yas = models.IntegerField()
🔹 IntegerField → Tam sayı alanıdır.
🔹 Öğrencinin yaşı burada tutulur.
Yani:
Bu alan sadece sayı kabul eder (örneğin 14, 15, 16 gibi).
numara = models.CharField(max_length=20, unique=True)
🔹 Öğrenci numarası.
🔹 En fazla 20 karakter olabilir.
🔹 unique=True → Bu çok önemli!
Bu şunu yapar:
Aynı öğrenci numarası iki kez kaydedilemez.
Yani veritabanı seviyesinde benzersizlik garantisi verir.
kayit_tarihi = models.DateTimeField(auto_now_add=True)
🔹 DateTimeField → Tarih + saat bilgisini tutar.
🔹 auto_now_add=True → Kayıt oluşturulduğu anda otomatik olarak o anın tarih ve saatini yazar.
Yani:
Öğrenci sisteme eklendiği an otomatik olarak kayıt tarihi kaydedilir.
Bu alanı manuel dolduramazsın.
def __str__(self):
🔹 Python’da özel bir metottur.
🔹 Model nesnesi yazdırıldığında nasıl görüneceğini belirler.
Örneğin Django Admin panelinde burada yazan değer görünür.
return f"{self.ad} {self.soyad}"
🔹 f-string kullanılmıştır.
🔹 self.ad → öğrencinin adı
🔹 self.soyad → öğrencinin soyadı
Yani admin panelde öğrenci şu şekilde görünür:
Ahmet Yılmaz
Eğer bu metot olmasaydı admin panelde şöyle görünürdü:
Ogrenci object (1)
📌 Bu Model Ne Yapar?
Bu model veritabanında şöyle bir tablo oluşturur:
| id | ad | soyad | yas | numara | kayit_tarihi |
|---|
🎯 Özet
Bu model:
✅ Öğrenci adı
✅ Soyadı
✅ Yaşı
✅ Benzersiz öğrenci numarası
✅ Otomatik kayıt tarihi
tutan bir Django veritabanı tablosudur.
🔄 4️⃣ Migration
python manage.py makemigrations
python manage.py migrate
Django’da model yazdıktan sonra veritabanına yansıtmak için bu iki adım zorunludur.
Şimdi tek tek ve mantığıyla açıklayalım:
1️⃣ python manage.py makemigrations
🔹 Ne yapar?
Bu komut:
Yazdığın modelleri kontrol eder ve değişiklikleri bir “migration dosyasına” çevirir.
Yani:
Model ekledin mi?
Alan ekledin mi?
Alan sildin mi?
max_length değiştirdin mi?
Hepsini algılar ve bir plan oluşturur.
🔹 Teknik olarak ne olur?
makemigrations komutunu çalıştırınca Django şunu yapar:
migrations klasörü oluşturur (yoksa)
İçine şöyle bir dosya ekler:
0001_initial.py
Yani aslında:
Django senin modelini Python koduna çevirir.
Ama henüz veritabanına dokunmaz ❗
2️⃣ python manage.py migrate
🔹 Ne yapar?
Bu komut:
Oluşturulan migration dosyalarını veritabanına uygular.
Yani:
Tabloyu gerçekten oluşturur
Sütunları ekler
Değişiklikleri uygular
🔹 Önemli fark
Komut Ne Yapar? makemigrations Değişiklik planı hazırlar migrate Planı veritabanına uygular
🎯 Gerçek Hayat Benzetmesi
Diyelim ki bir ev yapıyorsun:
📝 makemigrations → Mimari plan çizmek
🏗 migrate → Evi gerçekten inşa etmek
📌 Komut Sırası
Her zaman şu sırayla çalıştırılır:
python manage.py makemigrations
python manage.py migrate
🔥 Eğer migrate çalıştırmazsan ne olur?
Admin paneline girersin ve şu hatayı alırsın:
no such table: app_adi_ogrenci
Çünkü tablo fiziksel olarak oluşmamıştır.
💡 Ekstra Bilgi (Çok Önemli)
Eğer modelde değişiklik yaparsan:
yas = models.IntegerField()
ekledin diyelim.
Tekrar şunları yapman gerekir:
python manage.py makemigrations
python manage.py migrate
🧠 Özet
makemigrations → Model değişikliklerini algılar ve migration dosyası üretir
migrate → Bu dosyayı veritabanına uygular
Bu iki adım olmadan model çalışmaz
🧾 5️⃣ Form Oluşturma
📁 ogrenci/forms.py
from django import forms
from .models import Ogrenci
class OgrenciForm(forms.ModelForm):
class Meta:
model = Ogrenci
fields = '__all__'
Bu artık Django’nun ModelForm kısmı.
Model ile formu otomatik bağlayan profesyonel yöntemdir.
Kodunu satır satır açıklayalım:
from django import forms
🔹 Django’nun form sistemini içe aktarır.
🔹 forms modülü sayesinde form sınıfları oluşturabiliriz.
Yani:
HTML form üretmemizi sağlayan Django modülünü kullanıyoruz.
from .models import Ogrenci
🔹 Aynı klasördeki (.) models.py dosyasından
🔹 Ogrenci modelini içe aktarır.
Bu neden gerekli?
Çünkü birazdan formu bu modele bağlayacağız.
🔥 Asıl önemli kısım
class OgrenciForm(forms.ModelForm):
🔹 OgrenciForm adında bir form sınıfı oluşturuyoruz.
🔹 forms.ModelForm’dan kalıtım alıyor.
ModelForm ne demek?
ModelForm şunu yapar:
Modeldeki alanları otomatik olarak form alanına çevirir.
Yani sen tek tek şunu yazmazsın:
ad = forms.CharField()
soyad = forms.CharField()
yas = forms.IntegerField()
Django modeli okuyup formu otomatik üretir.
İç Sınıf: Meta
class Meta:
🔹 Bu özel bir ayar sınıfıdır.
🔹 Formun hangi modele bağlı olduğunu burada belirtiriz.
model = Ogrenci
🔹 Bu formun bağlı olduğu model: Ogrenci
Yani:
Bu form Ogrenci tablosu için kullanılacak.
fields = '__all__'
🔹 Modeldeki tüm alanları forma dahil eder.
Yani şu alanların hepsi formda çıkar:
ad
soyad
yas
numara
kayit_tarihi
⚠️ Önemli Not
Eğer kayit_tarihi otomatik alan olduğu için görünmesini istemezsen şunu yapabilirsin:
fields = ['ad', 'soyad', 'yas', 'numara']
veya
exclude = ['kayit_tarihi']
🎯 Bu Form Ne İşe Yarar?
Bu form sayesinde:
✅ Öğrenci ekleme
✅ Öğrenci güncelleme
✅ Form doğrulama (validation)
✅ Hata mesajı gösterme
işlemleri otomatik yapılır.
🔥 Django Arkada Ne Yapıyor?
ModelForm şunları otomatik yapar:
Veriyi doğrular
unique alanı kontrol eder (numara tekrar edemez)
IntegerField sayı mı kontrol eder
max_length sınırını kontrol eder
Yani ekstra kod yazmadan güvenli form elde edersin.
📌 Özet
Kod Ne Yapar forms.ModelForm Modelden otomatik form üretir model = Ogrenci Hangi modele bağlı fields = 'all' Tüm alanları kullan
👁 6️⃣ Views (CRUD İşlemleri)
📁 ogrenci/views.py
from django.shortcuts import render, redirect, get_object_or_404
from .models import Ogrenci
from .forms import OgrenciForm
# Listeleme
def ogrenci_list(request):
ogrenciler = Ogrenci.objects.all()
return render(request, 'ogrenci/list.html', {'ogrenciler': ogrenciler})
# Ekleme
def ogrenci_create(request):
form = OgrenciForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('ogrenci_list')
return render(request, 'ogrenci/form.html', {'form': form})
# Güncelleme
def ogrenci_update(request, pk):
ogrenci = get_object_or_404(Ogrenci, pk=pk)
form = OgrenciForm(request.POST or None, instance=ogrenci)
if form.is_valid():
form.save()
return redirect('ogrenci_list')
return render(request, 'ogrenci/form.html', {'form': form})
# Silme
def ogrenci_delete(request, pk):
ogrenci = get_object_or_404(Ogrenci, pk=pk)
ogrenci.delete()
return redirect('ogrenci_list')
👌 Bu artık tam bir CRUD sistemi (Create, Read, Update, Delete).
Şimdi kodlarını satır satır, mantığıyla ve profesyonel seviyede açıklıyorum.
📌 Import Satırları
from django.shortcuts import render, redirect, get_object_or_404
🔹 render
HTML dosyasını ekrana basmak için kullanılır.
🔹 redirect
Başka bir URL’e yönlendirme yapar.
🔹 get_object_or_404
Veritabanında obje bulamazsa otomatik 404 hatası verir.
from .models import Ogrenci
Ogrenci modelini içe aktarıyoruz.
Veritabanı işlemleri için gerekli.
from .forms import OgrenciForm
ModelForm’u içe aktarıyoruz.
Form işlemleri için kullanacağız.
📖 Listeleme (READ)
def ogrenci_list(request):
Bir view fonksiyonu tanımlıyoruz.
Her view fonksiyonu ilk parametre olarak request alır.
ogrenciler = Ogrenci.objects.all()
Ne yapıyor?
Ogrenci tablosundaki tüm kayıtları alır.
SQL karşılığı:
SELECT * FROM ogrenci;
objects → Django ORM yöneticisi
all() → Tüm kayıtları getir
return render(request, 'ogrenci/list.html', {'ogrenciler': ogrenciler})
list.html sayfasını açar
ogrenciler verisini template’e gönderir
Template içinde şöyle kullanılır:
{% for ogrenci in ogrenciler %}
{{ ogrenci.ad }}
{% endfor %}
➕ Ekleme (CREATE)
def ogrenci_create(request):
Yeni öğrenci ekleme view’i.
form = OgrenciForm(request.POST or None)
Çok önemli satır 👇
Eğer form gönderildiyse → POST verisini alır
Sayfa ilk açıldığında → None olur
Yani hem GET hem POST’u aynı yerde yönetiyoruz.
if form.is_valid():
Form doğrulama:
Boş alan var mı?
max_length aşıldı mı?
unique alan tekrar mı?
sayı alanına yazı mı girildi?
Hepsini kontrol eder.
form.save()
Bu satır:
Formdaki veriyi veritabanına kaydeder.
Arka planda şunu yapar:
Ogrenci.objects.create(...)
return redirect('ogrenci_list')
Kaydettikten sonra liste sayfasına yönlendirir.
Bu isim urls.py içindeki name değeridir.
return render(request, 'ogrenci/form.html', {'form': form})
Eğer form geçersizse:
Aynı sayfa tekrar açılır
Hata mesajları gösterilir
✏️ Güncelleme (UPDATE)
def ogrenci_update(request, pk):
Buradaki pk:
primary key (id)
Yani hangi öğrenciyi düzenleyeceğimizi belirler.
ogrenci = get_object_or_404(Ogrenci, pk=pk)
Veritabanında pk’ye göre arar
Bulamazsa 404 verir
SQL karşılığı:
SELECT * FROM ogrenci WHERE id = pk;
form = OgrenciForm(request.POST or None, instance=ogrenci)
⚠️ İşte güncellemenin sırrı burada:
instance=ogrenci
Bu şunu yapar:
Yeni kayıt oluşturma, mevcut kaydı güncelle.
Eğer instance yazmazsan yeni kayıt açılır ❗
if form.is_valid():
form.save()
Bu sefer save() şunu yapar:
UPDATE ogrenci SET ...
return redirect('ogrenci_list')
Güncellemeden sonra listeye döner.
return render(request, 'ogrenci/form.html', {'form': form})
Aynı form sayfasını kullanıyoruz.
Hem create hem update için tek form template’i.
Bu profesyonel yaklaşımdır 👍
❌ Silme (DELETE)
def ogrenci_delete(request, pk):
Silme view’i.
ogrenci = get_object_or_404(Ogrenci, pk=pk)
Silinecek öğrenciyi bulur.
ogrenci.delete()
Veritabanından siler.
SQL karşılığı:
DELETE FROM ogrenci WHERE id = pk;
return redirect('ogrenci_list')
Silme işleminden sonra listeye yönlendirir.
🎯 Bu Kodun Tam Mantığı
İşlem Fonksiyon SQL Karşılığı Listeleme ogrenci_list SELECT Ekleme ogrenci_create INSERT Güncelleme ogrenci_update UPDATE Silme ogrenci_delete DELETE
🧠 Çok Önemli Profesyonel Noktalar
✅ ModelForm kullanılmış → Temiz kod
✅ instance kullanılmış → Doğru update
✅ get_object_or_404 kullanılmış → Güvenli
✅ Aynı form template’i kullanılmış → DRY prensibi
🌐 7️⃣ URL Yapısı
📁 ogrenci/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.ogrenci_list, name='ogrenci_list'),
path('ekle/', views.ogrenci_create, name='ogrenci_create'),
path('guncelle/<int:pk>/', views.ogrenci_update, name='ogrenci_update'),
path('sil/<int:pk>/', views.ogrenci_delete, name='ogrenci_delete'),
]
📁 okulproje/urls.py
from django.urls import path, include
urlpatterns = [
path('', include('ogrenci.urls')),
]
🎨 8️⃣ Templates
📁 templates/ogrenci/list.html
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>Öğrenci Listesi</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container mt-5">
<h2>Öğrenci Listesi</h2>
<a href="{% url 'ogrenci_create' %}" class="btn btn-success mb-3">Yeni Öğrenci</a>
<table class="table table-bordered">
<tr>
<th>Ad</th>
<th>Soyad</th>
<th>Yaş</th>
<th>Numara</th>
<th>İşlemler</th>
</tr>
{% for ogrenci in ogrenciler %}
<tr>
<td>{{ ogrenci.ad }}</td>
<td>{{ ogrenci.soyad }}</td>
<td>{{ ogrenci.yas }}</td>
<td>{{ ogrenci.numara }}</td>
<td>
<a href="{% url 'ogrenci_update' ogrenci.id %}" class="btn btn-warning btn-sm">Güncelle</a>
<a href="{% url 'ogrenci_delete' ogrenci.id %}" class="btn btn-danger btn-sm">Sil</a>
</td>
</tr>
{% endfor %}
</table>
</body>
</html>
📁 templates/ogrenci/form.html
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<title>Öğrenci Form</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container mt-5">
<h2>Öğrenci Formu</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Kaydet</button>
</form>
</body>
</html>
👍 Şimdi bu HTML + Django template kodunu satır satır ve mantığıyla açıklayalım.
Bu kod bir Django formunu template içinde göstermeye yarar.
🔹 1️⃣ Form Açılışı
<form method="post">
Ne demek?
<form> → HTML form başlatır.
method="post" → Form verileri POST yöntemiyle gönderilecek demektir.
Neden POST?
HTTP’de iki temel yöntem vardır:
Method Ne İçin Kullanılır GET Veri çekmek POST Veri göndermek / kaydetmek
Biz burada veritabanına kayıt yapacağımız için POST kullanıyoruz.
🔹 CSRF Koruması
{% csrf_token %}
Bu ne?
Django’nun güvenlik sistemidir.
CSRF = Cross Site Request Forgery
Ne işe yarar?
Bir saldırganın senin sitene sahte form gönderip veri eklemesini engeller.
Django POST yapılan her formda bu token’ı zorunlu tutar.
Eğer bunu koymazsan şu hatayı alırsın:
403 Forbidden (CSRF verification failed)
Yani bu satır:
Formu güvenli hale getirir.
🔹 3️⃣ Formu Gösterme
{{ form.as_p }}
Burada Django’nun ModelForm’u ekrana basılıyor.
Ne yapar?
Form alanlarını otomatik üretir.
Örneğin modelin şöyleyse:
ad = models.CharField(...)
soyad = models.CharField(...)
Ekranda şunlar oluşur:
<p>
<label>Ad:</label>
<input type="text">
</p>
<p>
<label>Soyad:</label>
<input type="text">
</p>
🔹 as_p ne demek?
Kullanım Açıklama form.as_p Her alanı <p> içine koyar form.as_table <table> formatında yaparform.as_ul <ul><li> formatında yapar
Yani:
{{ form.as_p }}
Formu paragraf yapısında gösterir.
🔹 4️⃣ Submit Butonu
<button type="submit" class="btn btn-primary">Kaydet</button>
Parçalayalım:
type="submit" → Formu gönderir
class="btn btn-primary" → Bootstrap stil sınıfı
Kaydet → Buton yazısı
Tıklanınca ne olur?
Form POST edilir
View’daki şu kısım çalışır:
if form.is_valid():
form.save()
🔥 Formun Tam Çalışma Mantığı
Kullanıcı sayfayı açar → GET isteği
Form boş gelir
Kullanıcı doldurur
Kaydet’e basar
POST olur
Django doğrular
Geçerliyse kaydeder
Listeye yönlendirir
🎯 Görsel Olarak Süreç
Template → POST → View → is_valid → save → redirect
⚠️ Profesyonel Not
Bu kullanım hızlıdır ama tasarım zayıftır.
Daha profesyonel yöntem:
{% for field in form %}
<div class="mb-3">
{{ field.label_tag }}
{{ field }}
{{ field.errors }}
</div>
{% endfor %}
Bu şekilde Bootstrap uyumlu modern form yapılır.
📌 Özet
Satır Ne Yapar <form method="post"> POST ile veri gönderir {% csrf_token %} Güvenlik sağlar {{ form.as_p }} Form alanlarını gösterir <button type="submit"> Formu gönderir
🚀 9️⃣ Projeyi Çalıştır
python manage.py runserver
Tarayıcıda:
http://127.0.0.1:8000/
📊 Bu Projede Öğrendiklerin
✔ Model oluşturma
✔ Migration
✔ ModelForm
✔ CRUD mantığı
✔ URL – View – Template bağlantısı
✔ Bootstrap tablo tasarımı
Yorumlar
Yorum Gönder