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

KomutNe 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

KodNe 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ığı

İşlemFonksiyon    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:

MethodNe İç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ımAçıklama
form.as_p            Her alanı <p> içine koyar
form.as_table<table>     formatında yapar
form.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?

  1. Form POST edilir

  2. View’daki şu kısım çalışır:

if form.is_valid():
    form.save()

🔥 Formun Tam Çalışma Mantığı

  1. Kullanıcı sayfayı açar → GET isteği

  2. Form boş gelir

  3. Kullanıcı doldurur

  4. Kaydet’e basar

  5. POST olur

  6. Django doğrular

  7. Geçerliyse kaydeder

  8. 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ırNe 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

Bu blogdaki popüler yayınlar

Pardus Üzerine Django Kurulumu

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