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.
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.
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.
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çinclean_ö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.
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.
<!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:
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:
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.
<!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'inform-control,form-labelgibi 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-feedbackstiliyle 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.
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 table, table-striped ve table-hover sınıflarını kullanarak temiz ve okunabilir bir tasarım elde edeceğiz.
<!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.
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.
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:
<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:
<!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?
ModelFormneden 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
| Alan | Açı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ür | Açı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?
Kullanıcı formu doldurur
POST isteği gelir
form.is_valid()çalışırValidation kontrol edilir
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:
Field temizleme
clean_<field>()clean()Model validation
Hata varsa
form.errorsdolu 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 | Form | ModelForm |
|---|---|---|
| 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:
Başlık en fazla 50 karakter olsun.
İçerik en az 10 karakter olsun.
Aynı başlık tekrar eklenemesin.
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
| Signal | Ne Zaman Çalışır |
|---|---|
| pre_save | Kaydetmeden önce |
| post_save | Kaydettikten sonra |
| pre_delete | Silmeden önce |
| post_delete | Sildikten sonra |
| m2m_changed | ManyToMany 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
| Alan | Tür | Açı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ı
DuaFormoluşturulmalıForm doğrulama sistemi aktif çalışmalı
Hatalar kullanıcıya gösterilmeli
5️⃣ Django Signals
Yeni model oluştur:
Log Modeli
| Alan | Tür |
|---|---|
| mesaj | TextField |
| tarih | DateTimeField (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:
Custom validator neden model içinde tanımlanır?
Unique Constraint ile unique=True arasındaki fark nedir?
Signal kullanmanın avantajları nelerdir?
form.is_valid() çalıştığında arka planda neler olur?
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
Yorum Gönder