Django'da Veri Akışı: Modeller, Formlar ve Veri Doğrulama (Validation)

Django'nun en güçlü olduğu alanlardan biri, kullanıcıdan alınan verinin doğrulanması (validation) ve veritabanına (models) güvenli bir şekilde kaydedilmesidir.



Web uygulamalarında en kritik süreçlerden biri kullanıcıdan veri almak, bu verinin kurallara uygun olup olmadığını denetlemek (doğrulama) ve ardından güvenli bir şekilde veritabanına kaydetmektir. Django, bu üçlüyü (Model, Form, Validation) kusursuz bir uyum içinde yönetmemizi sağlayan harika bir altyapı sunar.

Bir "Öğrenci Kayıt" sistemi üzerinden veritabanı modelimizi oluşturacak, bu modele bağlı bir form üretecek ve girilen verileri doğrulayarak kaydedeceğiz.

1. Veritabanı İskeleti: Modeller (models.py)

Her şey veritabanımızın tasarımına karar vermekle başlar. Django'da veritabanı tablolarımızı Python sınıfları (class) olarak tanımlarız.

Python:
from django.db import models

class Ogrenci(models.Model):
    ad_soyad = models.CharField(max_length=100, verbose_name="Ad Soyad")
    eposta = models.EmailField(unique=True, verbose_name="E-Posta Adresi")
    yas = models.IntegerField(verbose_name="Yaş")
    kayit_tarihi = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.ad_soyad

Bu model, veritabanımızda Ogrenci adında bir tablo oluşturur. EmailField kullanarak e-posta formatı için ilk temel doğrulama kuralını veritabanı seviyesinde koymuş olduk. unique=True ise aynı e-postanın ikinci kez kaydedilmesini engeller.

2. Kullanıcı Arayüzü Köprüsü: ModelForm (forms.py)

Veritabanımızı oluşturduk. Peki kullanıcıdan bu bilgileri nasıl alacağız? HTML formlarını elle yazmak ve her bir input alanını tek tek kontrol etmek yerine, Django'nun ModelForm yapısını kullanırız. ModelForm, var olan bir modelden otomatik olarak form üretir.

Aynı zamanda Veri Doğrulama (Validation) işlemlerinin kalbi burasıdır.

Python:
from django import forms
from .models import Ogrenci
from django.core.exceptions import ValidationError

class OgrenciForm(forms.ModelForm):
    class Meta:
        model = Ogrenci
        fields = ['ad_soyad', 'eposta', 'yas']
        # kayit_tarihi otomatik eklendiği için forma dahil etmiyoruz.

    # Özel Veri Doğrulama (Custom Validation)
    def clean_yas(self):
        yas = self.cleaned_data.get('yas')
        if yas < 18:
            raise ValidationError("Kayıt olabilmek için 18 yaşından büyük olmalısınız.")
        return yas

    def clean_ad_soyad(self):
        ad_soyad = self.cleaned_data.get('ad_soyad')
        if len(ad_soyad) < 5:
            raise ValidationError("Ad soyad çok kısa. Lütfen tam adınızı girin.")
        return ad_soyad

Neler Yaptık?

  • clean_<alan_adi> Metotları: Django'da belirli bir alanı doğrulamak için clean_ önekiyle metotlar yazarız.

  • Kullanıcı formu gönderdiğinde, Django önce alanların kendi veri tiplerini (sayı mı, e-posta mı?) kontrol eder. Ardından bizim yazdığımız bu özel doğrulama kurallarını çalıştırır. Eğer kurallara uymazsa, hata mesajı (ValidationError) üretilir ve kayıt engellenir.

3. Trafik Polisi: Görünümler (views.py)

Kullanıcının formu göreceği ve doldurup göndereceği (POST) süreci View katmanında yönetiriz.

Python:
from django.shortcuts import render, redirect
from .forms import OgrenciForm

def ogrenci_kayit_view(request):
    # Kullanıcı formu doldurup 'Gönder' butonuna bastıysa (POST isteği)
    if request.method == 'POST':
        form = OgrenciForm(request.POST)
        
        # form.is_valid() fonksiyonu forms.py'deki tüm doğrulama kurallarını çalıştırır.
        if form.is_valid():
            # Kurallar geçildiyse, veriyi doğrudan veritabanına kaydet
            form.save() 
            return redirect('basarili_kayit_sayfasi') # Kayıt sonrası başka sayfaya yönlendir
            
    # Kullanıcı sayfaya ilk defa giriyorsa (GET isteği), boş formu göster
    else:
        form = OgrenciForm()

    return render(request, 'ogrenci_kayit.html', {'form': form})

Buradaki sihir form.is_valid() fonksiyonundadır. Bu fonksiyon çağrıldığında Django arka planda formdaki e-posta adresinin geçerli olup olmadığını, kullanıcının 18 yaşından büyük olup olmadığını kontrol eder. Hata yoksa True döner ve form.save() ile veri doğrudan modele (ve dolayısıyla veritabanına) yazılır.

4. Kullanıcıya Sunum: Şablonlar (ogrenci_kayit.html)

Son adımda, hazırladığımız formu HTML sayfasında ekrana basıyoruz. Django form hatalarını da otomatik olarak arayüze taşır.

HTML:
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <title>Öğrenci Kayıt Formu</title>
</head>
<body>
    <h2>Yeni Öğrenci Kaydı</h2>

    <form method="POST">
        {% csrf_token %} 
        
        {{ form.as_p }} 
        
        <button type="submit">Kaydet</button>
    </form>
</body>
</html>

Eğer kullanıcı yas alanına 15 girerse, form gönderildiğinde is_valid() False dönecek, sayfa yeniden yüklenecek ve formun hemen yanında bizim forms.py'de yazdığımız "Kayıt olabilmek için 18 yaşından büyük olmalısınız." uyarısı belirecektir.

Özet

Django'nun form ve model mimarisi, veriyi veritabanı tabloları ile eşleştirme ve temizleme (doğrulama) yükünü omuzlarımızdan alır. Güvenli ve tutarlı bir veri akışı için ModelForm yapısı ve is_valid() fonksiyonu en iyi dostumuzdur.




5. Formları Güzelleştirmek: Bootstrap ve Crispy Forms Entegrasyonu

Django'nun standart HTML çıktısı olan {{ form.as_p }} oldukça işlevseldir, ancak görsel olarak günümüz modern web standartlarının gerisinde kalabilir. Hazırladığımız projelere profesyonel, mobil uyumlu (responsive) ve şık bir dokunuş katmak için en pratik yöntem Bootstrap CSS iskeletini ve django-crispy-forms paketini birlikte kullanmaktır.

Bu paket, Django formlarınızı otomatik olarak Bootstrap sınıfları (class) ile sarmalayarak harika bir görünüm elde etmenizi sağlar.

Adım 1: Gerekli Paketlerin Kurulumu

Öncelikle terminal veya komut satırımızı (Pardus veya macOS terminalinizde sanal ortamınız aktifken) açıp aşağıdaki paketleri projemize kuruyoruz:

Bash:
pip install django-crispy-forms
pip install crispy-bootstrap5

Adım 2: Ayarların Yapılandırılması (settings.py)

Kurduğumuz paketleri Django'ya tanıtmamız gerekiyor. settings.py dosyanızı açın ve INSTALLED_APPS listenize bu iki uygulamayı ekleyin:

Python:
INSTALLED_APPS = [
    # ... Django'nun varsayılan uygulamaları ...
    'crispy_forms',
    'crispy_bootstrap5',
    # 'kendi_uygulamaniz',
]

# Crispy Forms'un varsayılan olarak Bootstrap 5 şablonlarını kullanmasını söylüyoruz:
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"

Adım 3: Şablonda Kullanım (ogrenci_kayit.html)

Şimdi, daha önce oluşturduğumuz HTML şablonumuzu güncelliyoruz. Sayfamıza Bootstrap'in CSS dosyasını ekleyecek ve formumuzu crispy filtresinden geçireceğiz.

HTML:
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Öğrenci Kayıt Formu</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">

    <div class="container mt-5">
        <div class="row justify-content-center">
            <div class="col-md-6">
                <div class="card shadow-sm">
                    <div class="card-header bg-primary text-white">
                        <h4 class="mb-0">Yeni Öğrenci Kaydı</h4>
                    </div>
                    <div class="card-body">
                        
                        {% load crispy_forms_tags %}
                        
                        <form method="POST" novalidate>
                            {% csrf_token %}
                            
                            {{ form|crispy }}
                            
                            <button type="submit" class="btn btn-success w-100 mt-4">Sisteme Kaydet</button>
                        </form>
                        
                    </div>
                </div>
            </div>
        </div>
    </div>

</body>
</html>

Neler Değişti?

  • {% load crispy_forms_tags %}: Bu satır, Crispy'nin yeteneklerini HTML sayfamızda kullanabilmemiz için gerekli kütüphaneyi içeri aktarır.

  • {{ form|crispy }}: Daha önce kullandığımız {{ form.as_p }} yerine bu filtreyi kullandık. Django formumuz artık doğrudan Bootstrap 5'in form-controlform-label gibi sınıflarıyla beraber HTML'e dönüştürülüyor.

  • Hata Yönetimi Görselliği: Eğer kullanıcı doğrulama kurallarımıza (validation) takılırsa (örneğin 18 yaşından küçük girerse), Crispy Forms bu hata mesajlarını otomatik olarak Bootstrap'in kırmızı renkli invalid-feedback stiliyle ve ilgili giriş kutusunu kırmızıya boyayarak ekrana basar. Ekstra hiçbir kod yazmamıza gerek kalmaz!


Bu, ünlü CRUD (Create, Read, Update, Delete) döngüsünün "Read" (Okuma) aşamasıdır.


6. Verileri Okumak ve Listelemek (CRUD - Read)

Kullanıcılardan form aracılığıyla aldığımız verileri veritabanına başarıyla kaydettik. Peki, bu kayıtlı öğrencileri nasıl göreceğiz? Django'nun ORM (Object-Relational Mapping) yapısı sayesinde, karmaşık SQL sorguları yazmadan veritabanımızdaki tüm kayıtlara tek satır Python koduyla ulaşabiliriz.

Şimdi bu verileri çekip, Bootstrap'in şık tablo sınıflarını kullanarak ekranda listeleyelim.

Adım 1: Verileri Çekmek (views.py)

Görünümler (views) dosyamızda yeni bir fonksiyon oluşturuyoruz. Bu fonksiyon, Ogrenci modelimizdeki tüm kayıtları alacak ve HTML şablonumuza gönderecek.

Python:
from django.shortcuts import render
from .models import Ogrenci

def ogrenci_liste_view(request):
    # Veritabanındaki tüm öğrenci kayıtlarını çekiyoruz
    ogrenciler = Ogrenci.objects.all().order_by('-kayit_tarihi') 
    
    # Çektiğimiz veriyi 'ogrenciler' anahtarıyla şablona gönderiyoruz (Context)
    context = {
        'ogrenciler': ogrenciler
    }
    
    return render(request, 'ogrenci_liste.html', context)

İpucu: .order_by('-kayit_tarihi') metodu sayesinde listemizi, en son kayıt olan öğrenci en üstte görünecek şekilde sıralamış olduk.

Adım 2: Tablo Tasarımı (ogrenci_liste.html)

Şimdi verileri karşılayacak ve döngüye sokarak ekrana basacak şablonumuzu hazırlayalım. Bootstrap'in tabletable-striped ve table-hover sınıflarını kullanarak temiz ve okunabilir bir tasarım elde edeceğiz.

HTML:
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Öğrenci Listesi</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">

    <div class="container mt-5">
        <div class="d-flex justify-content-between align-items-center mb-4">
            <h2>Kayıtlı Öğrenciler</h2>
            <a href="{% url 'ogrenci_kayit' %}" class="btn btn-primary">+ Yeni Öğrenci Ekle</a>
        </div>

        <div class="card shadow-sm">
            <div class="card-body p-0">
                <div class="table-responsive">
                    <table class="table table-striped table-hover mb-0">
                        <thead class="table-dark">
                            <tr>
                                <th>#</th>
                                <th>Ad Soyad</th>
                                <th>E-Posta</th>
                                <th>Yaş</th>
                                <th>Kayıt Tarihi</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for ogrenci in ogrenciler %}
                            <tr>
                                <td>{{ forloop.counter }}</td>
                                <td>{{ ogrenci.ad_soyad }}</td>
                                <td>{{ ogrenci.eposta }}</td>
                                <td>{{ ogrenci.yas }}</td>
                                <td>{{ ogrenci.kayit_tarihi|date:"d M Y, H:i" }}</td>
                            </tr>
                            {% empty %}
                            <tr>
                                <td colspan="5" class="text-center py-4 text-muted">
                                    Henüz kayıtlı öğrenci bulunmamaktadır.
                                </td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>

</body>
</html>

Neler Öğrendik?

  • Ogrenci.objects.all(): Veritabanındaki tabloya gidip tüm satırları bir Python listesi (QuerySet) olarak getirmemizi sağladı.

  • {% for ogrenci in ogrenciler %}: View'dan gönderdiğimiz listeyi HTML içinde döndürerek her bir satır için yeni bir <tr> (tablo satırı) oluşturduk.

  • {{ forloop.counter }}: Django'nun döngülerde sunduğu bu harika özellik sayesinde, ID numaralarından bağımsız olarak listeye 1, 2, 3 şeklinde otomatik sıra numarası verdik.

  • |date:"d M Y, H:i": Django template filtrelerini kullanarak karmaşık tarih formatını (Örn: 2026-03-03 14:30:00) kullanıcı dostu bir görünüme (03 Mar 2026, 14:30) dönüştürdük.




7. Tam Bir CRUD: Kayıt Güncelleme (Update) ve Silme (Delete)

Veri eklemeyi (Create) ve listelemeyi (Read) başardık. Ancak gerçek dünya uygulamalarında kullanıcılar hata yapabilir ve verilerini düzenlemek veya tamamen sistemden kaldırmak isteyebilirler. Django'nun ModelForm yapısı, güncelleme işlemini neredeyse baştan form yazmaya gerek kalmadan, mevcut yapımızı kullanarak çözmemizi sağlar.

Adım 1: Rota Ayarları (urls.py)

Hangi öğrencinin güncelleneceğini veya silineceğini sistemin bilmesi gerekir. Bunun için URL yapımıza öğrencinin benzersiz kimliğini (ID) parametre olarak ekliyoruz.

Python:
from django.urls import path
from . import views

urlpatterns = [
    # Önceki rotalarınız...
    path('ogrenci/liste/', views.ogrenci_liste_view, name='ogrenci_liste'),
    
    # Yeni rotalarımız (<int:id> kısmı, hangi öğrenciye işlem yapılacağını belirler)
    path('ogrenci/guncelle/<int:id>/', views.ogrenci_guncelle_view, name='ogrenci_guncelle'),
    path('ogrenci/sil/<int:id>/', views.ogrenci_sil_view, name='ogrenci_sil'),
]

Adım 2: Görünümler (views.py)

Şimdi, veritabanından ilgili öğrenciyi bulup (ID'sine göre) güncelleyecek ve silecek fonksiyonlarımızı yazalım.

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

# --- GÜNCELLEME İŞLEMİ ---
def ogrenci_guncelle_view(request, id):
    # İlgili öğrenciyi veritabanından bul, yoksa 404 Hata Sayfası göster
    ogrenci = get_object_or_404(Ogrenci, id=id)
    
    # Formu, veritabanından çektiğimiz bu öğrencinin (instance) bilgileriyle doldur
    form = OgrenciForm(request.POST or None, instance=ogrenci)
    
    if form.is_valid():
        form.save() # Var olan kaydın üzerine yazar
        return redirect('ogrenci_liste')
        
    # Mevcut ogrenci_kayit.html şablonumuzu güncelleme için de kullanabiliriz!
    return render(request, 'ogrenci_kayit.html', {'form': form})

# --- SİLME İŞLEMİ ---
def ogrenci_sil_view(request, id):
    ogrenci = get_object_or_404(Ogrenci, id=id)
    
    if request.method == 'POST':
        # Kullanıcı onay butonuna bastıysa kaydı sil ve listeye dön
        ogrenci.delete()
        return redirect('ogrenci_liste')
        
    # GET isteğinde (sayfa ilk açıldığında) silme onay ekranını göster
    return render(request, 'ogrenci_sil_onay.html', {'ogrenci': ogrenci})

Neden instance=ogrenci kullandık?

Django'nun harika özelliklerinden biri budur. OgrenciForm'a instance parametresini verdiğimizde, form boş gelmez; veritabanındaki mevcut bilgilerle (Örn: öğrencinin eski adı, eski e-postası) dolu olarak ekrana gelir.

Adım 3: Şablonları Güncellemek

Öncelikle, bir önceki derste hazırladığımız ogrenci_liste.html dosyamızdaki tabloya "Düzenle" ve "Sil" butonlarını ekleyelim. <tbody> içindeki ilgili satırı şu şekilde güncelleyin:

HTML:
<td>
    <a href="{% url 'ogrenci_guncelle' ogrenci.id %}" class="btn btn-sm btn-warning">Düzenle</a>
    
    <a href="{% url 'ogrenci_sil' ogrenci.id %}" class="btn btn-sm btn-danger">Sil</a>
</td>

Son olarak, silme işlemi geri alınamaz bir işlem olduğu için kullanıcıdan son bir onay alacağımız basit bir şablon olan ogrenci_sil_onay.html dosyasını oluşturalım:

HTML:
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <title>Silme Onayı</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="bg-light">
    <div class="container mt-5">
        <div class="alert alert-danger text-center shadow-sm">
            <h4>Emin misiniz?</h4>
            <p><strong>{{ ogrenci.ad_soyad }}</strong> isimli öğrencinin kaydını kalıcı olarak silmek üzeresiniz.</p>
            
            <form method="POST">
                {% csrf_token %}
                <a href="{% url 'ogrenci_liste' %}" class="btn btn-secondary">Vazgeç, Geri Dön</a>
                <button type="submit" class="btn btn-danger">Evet, Kaydı Sil</button>
            </form>
        </div>
    </div>
</body>
</html>

Sonuç

Modellerden başlayarak, form doğrulama işlemlerini (validation) gerçekleştirdiğimiz, Bootstrap ve Crispy Forms ile şıklaştırdığımız ve nihayetinde Create, Read, Update, Delete (CRUD) adımlarının tamamını barındıran tam fonksiyonel bir Django projesi inşa ettik.



Django Formları, Veri Doğrulama ve Model (Veritabanı) Entegrasyonu

🎯 Amaç

Bu makalede:

  • Django Model nedir?

  • Django Form nedir?

  • Form ile veritabanına kayıt nasıl yapılır?

  • Veri doğrulama (Validation) nasıl çalışır?

  • ModelForm neden kullanılır?

sorularını örnek bir uygulama üzerinden öğreneceğiz.


📌 Senaryo: “Dua Ekleme Sistemi”

Bir web uygulaması yapıyoruz:

  • Kullanıcı dua ekleyebilecek

  • Eklenen dualar veritabanına kaydedilecek

  • Boş alan bırakılırsa hata verecek

  • Karakter sınırı olacak

  • Özel doğrulama yapılacak


1️⃣ Django Model (Veritabanı Yapısı)

📂 models.py

from django.db import models

class Dua(models.Model):
    baslik = models.CharField(max_length=100)
    icerik = models.TextField()
    eklenme_tarihi = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.baslik

🔎 Açıklama

AlanAçıklama
CharField        Kısa metin
TextField        Uzun metin
auto_now_add=True        Otomatik tarih ekler
max_length=100        Maksimum 100 karakter

Migration

python manage.py makemigrations
python manage.py migrate

Bu işlem veritabanında tablo oluşturur.


2️⃣ Django Form Nedir?

Formlar:

  • Kullanıcıdan veri alır

  • Doğrulama yapar

  • Hataları yönetir

  • Veriyi modele aktarabilir


3️⃣ ModelForm Kullanımı (En Profesyonel Yöntem)

📂 forms.py

from django import forms
from .models import Dua

class DuaForm(forms.ModelForm):

    class Meta:
        model = Dua
        fields = ['baslik', 'icerik']

🎯 ModelForm Avantajı

  • Model ile otomatik bağlantı

  • Otomatik doğrulama

  • Kod tekrarını azaltır


4️⃣ Özel Veri Doğrulama (Validation)

Şimdi özel kurallar ekleyelim.

📂 forms.py

class DuaForm(forms.ModelForm):

    class Meta:
        model = Dua
        fields = ['baslik', 'icerik']

    def clean_baslik(self):
        baslik = self.cleaned_data.get('baslik')

        if len(baslik) < 3:
            raise forms.ValidationError("Başlık en az 3 karakter olmalıdır.")

        return baslik

    def clean(self):
        cleaned_data = super().clean()
        icerik = cleaned_data.get("icerik")

        if icerik and "küfür" in icerik.lower():
            raise forms.ValidationError("Uygunsuz kelime içeremez.")

        return cleaned_data

🔎 Doğrulama Türleri

TürAçıklama
Field Validation            Tek alan kontrolü
Form Validation            Tüm form kontrolü
Model Validation            Model seviyesinde kontrol

5️⃣ View ile Form ve Model Bağlantısı

📂 views.py

from django.shortcuts import render, redirect
from .forms import DuaForm

def dua_ekle(request):
    if request.method == "POST":
        form = DuaForm(request.POST)

        if form.is_valid():
            form.save()
            return redirect("dua_listesi")
    else:
        form = DuaForm()

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

🔎 Süreç Nasıl İşler?

  1. Kullanıcı formu doldurur

  2. POST isteği gelir

  3. form.is_valid() çalışır

  4. Validation kontrol edilir

  5. Doğruysa form.save() ile veritabanına kaydedilir


6️⃣ Template (HTML)

📂 dua_ekle.html

<h2>Dua Ekle</h2>

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Kaydet</button>
</form>

{% if form.errors %}
    <div style="color:red;">
        {{ form.errors }}
    </div>
{% endif %}

7️⃣ Django’da Doğrulama Süreci (Önemli)

form.is_valid() çağrıldığında:

  1. Field temizleme

  2. clean_<field>()

  3. clean()

  4. Model validation

  5. Hata varsa form.errors dolu olur


8️⃣ Model İçinde Validation Yapmak

📂 models.py

from django.core.exceptions import ValidationError

class Dua(models.Model):
    baslik = models.CharField(max_length=100)
    icerik = models.TextField()

    def clean(self):
        if "yasak" in self.baslik.lower():
            raise ValidationError("Başlık yasak kelime içeremez.")

9️⃣ Form Türleri Karşılaştırma

Özellik                FormModelForm
Manuel alan tanımı
Model bağlantısı
Otomatik save()
Büyük projeler

🔟 Admin Panel ile Kontrol

Django admin’de görmek için:

📂 admin.py

from django.contrib import admin
from .models import Dua

admin.site.register(Dua)

/admin panelinden kayıtları görebilirsin.


🧪 Mini Lab Görevi (Öğrenci Uygulaması)

Aşağıdaki kuralları ekleyin:

  1. Başlık en fazla 50 karakter olsun.

  2. İçerik en az 10 karakter olsun.

  3. Aynı başlık tekrar eklenemesin.

  4. Eklenme tarihi otomatik gelsin.


🚀 Profesyonel Bilgi

Büyük projelerde:

  • Custom Validators kullanılır

  • Signals kullanılır

  • Class Based Views tercih edilir

  • Form widget özelleştirilir

  • Bootstrap ile modern tasarım yapılır


📌 Özet

Django’da:

  • Model → Veritabanı yapısı

  • Form → Kullanıcıdan veri alma

  • Validation → Veri kontrolü

  • View → İş mantığı

  • Template → Görsel arayüz

birlikte çalışır.




🚀 1️⃣ Custom Validator (Özel Doğrulayıcı)

Büyük projelerde validation kodu form içine yazılmaz.
Ayrı bir yerde tanımlanır → tekrar kullanılabilir olur.


📂 validators.py oluşturuyoruz

from django.core.exceptions import ValidationError
import re

def yasakli_kelime_kontrol(value):
    yasakli_kelimeler = ["küfür", "argo", "yasak"]

    for kelime in yasakli_kelimeler:
        if kelime in value.lower():
            raise ValidationError(f"'{kelime}' kelimesi kullanılamaz.")

def sadece_harf_kontrol(value):
    if not re.match(r'^[a-zA-ZğüşıöçĞÜŞİÖÇ ]+$', value):
        raise ValidationError("Sadece harf kullanabilirsiniz.")

📂 models.py içinde kullanımı

from django.db import models
from .validators import yasakli_kelime_kontrol, sadece_harf_kontrol

class Dua(models.Model):
    baslik = models.CharField(
        max_length=100,
        validators=[sadece_harf_kontrol]
    )
    icerik = models.TextField(
        validators=[yasakli_kelime_kontrol]
    )
    eklenme_tarihi = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.baslik

🎯 Neden Bu Yöntem?

✔ Kod tekrarını önler
✔ Model seviyesinde çalışır
✔ Admin panelde de geçerlidir
✔ API'de de çalışır


🔒 2️⃣ Unique Constraint (Gelişmiş Benzersizlik)

Normalde:

baslik = models.CharField(max_length=100, unique=True)

Ama bu basit yöntemdir.

Biz profesyonel yöntem yapıyoruz.


🎯 Senaryo

Aynı başlık:

  • Aynı gün içinde tekrar eklenemesin

  • Farklı günlerde eklenebilsin


📂 models.py

from django.db import models
from django.db.models import UniqueConstraint
from django.db.models.functions import TruncDate

class Dua(models.Model):
    baslik = models.CharField(max_length=100)
    icerik = models.TextField()
    eklenme_tarihi = models.DateTimeField(auto_now_add=True)

    class Meta:
        constraints = [
            UniqueConstraint(
                TruncDate('eklenme_tarihi'),
                'baslik',
                name='unique_daily_dua'
            )
        ]

🎯 Bu Ne Sağladı?

Aynı başlık:

❌ Aynı gün tekrar edemez
✔ Ertesi gün tekrar edebilir

Bu gerçek projelerde çok kullanılır.


⚡ 3️⃣ Django Signals (Otomatik Tetiklenen Kodlar)

Signals =
Model kaydedildiğinde otomatik çalışan kod.


🎯 Senaryo

Yeni dua eklendiğinde:

  • Otomatik log kaydı oluşturulsun

  • Ya da sayaç artsın

  • Ya da bildirim oluşsun


📂 signals.py oluştur

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Dua

@receiver(post_save, sender=Dua)
def dua_kaydedildi(sender, instance, created, **kwargs):
    if created:
        print(f"Yeni dua eklendi: {instance.baslik}")

📂 apps.py içine ekle

from django.apps import AppConfig

class DuaAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'dua_app'

    def ready(self):
        import dua_app.signals

🔥 Daha Profesyonel Signal Örneği

Log modeli oluşturalım

class Log(models.Model):
    mesaj = models.TextField()
    tarih = models.DateTimeField(auto_now_add=True)

Signal ile log üretelim

@receiver(post_save, sender=Dua)
def dua_log_olustur(sender, instance, created, **kwargs):
    if created:
        Log.objects.create(
            mesaj=f"{instance.baslik} başlıklı dua eklendi."
        )

🧠 Django Signal Türleri

SignalNe Zaman Çalışır
pre_saveKaydetmeden önce
post_saveKaydettikten sonra
pre_deleteSilmeden önce
post_deleteSildikten sonra
m2m_changedManyToMany değişince

📊 Profesyonel Mimari Yapı

Gerçek projede klasör yapısı:

dua_app/
│
├── models.py
├── forms.py
├── views.py
├── validators.py
├── signals.py
├── services.py

Büyük projelerde iş mantığı services.py içine taşınır.


🛑 Önemli Uyarı

Signals:

✔ Otomatik çalışır
❌ Fazla kullanılırsa performans düşer
❌ Debug zorlaşır

Büyük projelerde genelde:

  • Signals yerine service layer kullanılır

  • Ya da explicit function çağrılır


🎓 Mini Pro Lab Görevi

Aşağıdakileri yap:

1️⃣ Başlık sadece harf kabul etsin
2️⃣ İçerik minimum 20 karakter olsun
3️⃣ Aynı başlık aynı gün eklenemesin
4️⃣ Her kayıt sonrası Log modeli oluşsun
5️⃣ Silme işlemi yapılınca log kaydı oluşsun





📌 PERFORMANS GÖREVİ

Proje Adı: Gelişmiş Dua Yönetim Sistemi


🎯 AMAÇ

Bu görevde öğrenciler:

  • Django Model oluşturabilecek

  • ModelForm kullanabilecek

  • Custom Validator yazabilecek

  • Unique Constraint tanımlayabilecek

  • Django Signals kullanabilecek

  • Veritabanı ile entegre çalışabilecek


📂 SENARYO

Bir web uygulaması geliştirmeniz istenmektedir.

Kullanıcılar:

  • Dua ekleyebilecek

  • Aynı başlığı aynı gün tekrar ekleyemeyecek

  • Uygunsuz kelimeler filtrelenecek

  • Kayıt sonrası sistem otomatik log oluşturacak


📌 YAPILMASI GEREKENLER


1️⃣ Model Tasarımı

Aşağıdaki modeli oluşturunuz:

Dua Modeli

AlanTürAçıklama
baslik        CharField        Maksimum 100 karakter
icerik        TextField        Minimum 20 karakter
eklenme_tarihi        DateTimeField        Otomatik oluşmalı

2️⃣ Custom Validator

Ayrı bir validators.py dosyasında:

  • Başlık sadece harf içermeli

  • İçerikte yasaklı kelime kontrolü yapılmalı

Örnek yasaklı kelimeler:

küfür, argo, yasak

3️⃣ Unique Constraint

Aynı başlık:

❌ Aynı gün tekrar eklenememeli
✔ Farklı gün eklenebilmeli

Meta sınıfında constraint tanımlanmalıdır.


4️⃣ ModelForm Kullanımı

  • DuaForm oluşturulmalı

  • Form doğrulama sistemi aktif çalışmalı

  • Hatalar kullanıcıya gösterilmeli


5️⃣ Django Signals

Yeni model oluştur:

Log Modeli

AlanTür
mesajTextField
tarihDateTimeField (auto_now_add)

Signal ile:

  • Yeni dua eklenince log oluşmalı

  • Dua silinince log oluşmalı


📌 ARAYÜZ

  • Basit HTML form

  • CSRF token kullanılmalı

  • Hatalar gösterilmeli

  • Kayıt sonrası liste sayfasına yönlendirme yapılmalı


📊 DEĞERLENDİRME ÖLÇEĞİ (100 PUAN)

Kriter        Puan
Model doğru tasarlanmış            15
Migration işlemleri doğru             5
Custom Validator doğru çalışıyor            20
Unique Constraint doğru            20
ModelForm doğru            10
View mantığı doğru            10
Signal sistemi doğru            15
Arayüz çalışır durumda              5

BONUS (10 PUAN)

Aşağıdakilerden birini yapınız:

  • Admin panel özelleştirme

  • Bootstrap tasarım

  • Silme işlemi için onay sayfası

  • Mesaj framework kullanımı

  • Class Based View kullanımı


📦 TESLİM ŞEKLİ

Öğrenci:

  • Proje klasörünü .zip olarak teslim edecek

  • README dosyasında:

    • Proje açıklaması

    • Kullanılan teknolojiler

    • Kurulum adımları

bulunmalıdır.


📝 RAPOR BÖLÜMÜ (Zorunlu)

Aşağıdaki sorular yazılı olarak cevaplanacaktır:

  1. Custom validator neden model içinde tanımlanır?

  2. Unique Constraint ile unique=True arasındaki fark nedir?

  3. Signal kullanmanın avantajları nelerdir?

  4. form.is_valid() çalıştığında arka planda neler olur?

  5. Migration neden gereklidir?


🎯 BEKLENEN KAZANIMLAR

Bu görevi tamamlayan öğrenci:

✅ Django veri doğrulama mantığını öğrenir
✅ Gerçek proje mimarisini görür
✅ Backend mantığını kavrar
✅ Veritabanı bütünlüğünü anlar
✅ Otomatik tetikleme sistemlerini öğrenir



Yorumlar

Bu blogdaki popüler yayınlar

Pardus Üzerine Django Kurulumu

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