Son güncelleme: Nisan 2026 · AnomixLabs Teknik Ekibi
CBV ve FBV birbirinin rakibi değil, tamamlayıcısıdır. Django'yu iyi bilen geliştirici her ikisini de kullanır — göreve göre doğru aracı seçer.
1. Function-Based Views (FBV)
FBV, bir Python fonksiyonu olarak yazılan view'dır. GET ve POST isteklerini request.method kontrolüyle ayrıştırır. Basitliği ve okunabilirliği güçlü yönleri:
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from .models import Article
from .forms import ArticleForm
@login_required
def article_create(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
article = form.save(commit=False)
article.author = request.user
article.save()
return redirect(article)
else:
form = ArticleForm()
return render(request, 'article_form.html', {'form': form})
2. Class-Based Views (CBV) — Generic Views
CBV, Django'nun sınıf hiyerarşisini kullanır. Generic view'lar standart CRUD kalıplarını minimal kodla sunar:
from django.views.generic import (
ListView, DetailView, CreateView, UpdateView, DeleteView
)
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
class ArticleListView(ListView):
model = Article
template_name = 'article_list.html'
context_object_name = 'articles'
paginate_by = 10
ordering = ['-created_at']
class ArticleDetailView(DetailView):
model = Article
slug_field = 'slug'
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
fields = ['title', 'content']
login_url = '/giris/'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class ArticleDeleteView(LoginRequiredMixin, DeleteView):
model = Article
success_url = reverse_lazy('article_list')
3. get_queryset ve get_context_data Override
class ArticleListView(ListView):
model = Article
def get_queryset(self):
# Sadece yayınlanmış makaleleri, N+1'den kaçınarak getir
return Article.objects.filter(
is_published=True,
).select_related('author', 'category')\
.prefetch_related('tags')
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['total_count'] = self.get_queryset().count()
ctx['categories'] = Category.objects.all()
return ctx
4. Mixin MRO Tuzağı
Birden fazla mixin kullanırken Python'ın Method Resolution Order (MRO) sırası kritiktir. LoginRequiredMixin her zaman birinci olmalıdır:
# DOĞRU — LoginRequiredMixin birinci
class ArticleCreateView(LoginRequiredMixin, CreateView):
...
# YANLIŞ — MRO çakışması, login redirect çalışmaz
class ArticleCreateView(CreateView, LoginRequiredMixin):
...
# Sırayı görmek için:
print(ArticleCreateView.__mro__)
5. Özel Mixin Yazmak
class AuthorRequiredMixin:
"""Yalnızca nesnenin sahibinin erişebildiği mixin."""
def get_object(self):
obj = super().get_object()
if obj.author != self.request.user:
from django.core.exceptions import PermissionDenied
raise PermissionDenied
return obj
class ArticleUpdateView(LoginRequiredMixin, AuthorRequiredMixin, UpdateView):
model = Article
fields = ['title', 'content']
6. FormView ile Özel Form Yönetimi
from django.views.generic.edit import FormView
class SearchView(FormView):
template_name = 'search.html'
form_class = SearchForm
success_url = '.' # Aynı sayfaya dön
def form_valid(self, form):
query = form.cleaned_data['query']
# Arama işlemi, session'a kaydet vb.
return super().form_valid(form)
7. Ne Zaman Hangisini Kullanmalı?
| Senaryo | Öneri | Neden? |
|---|---|---|
| Standart CRUD | CBV | Generic views kod azaltır |
| Karmaşık iş mantığı | FBV | Doğrusal akış okunması kolay |
| Webhook / API endpoint | FBV | Tek işlev, basit kalıp |
| Login gerektiren sayfalar | CBV (Mixin) | LoginRequiredMixin tekrar kullanılır |
| Tekrar eden kalıp | CBV | Mixin ile DRY |
8. Test Yazımı: FBV vs CBV
from django.test import TestCase, Client
from django.contrib.auth import get_user_model
User = get_user_model()
class ArticleViewTests(TestCase):
def setUp(self):
self.user = User.objects.create_user('ali', password='pass')
self.client = Client()
def test_list_view(self):
response = self.client.get('/makaleler/')
self.assertEqual(response.status_code, 200)
def test_create_requires_login(self):
response = self.client.get('/makaleler/yeni/')
self.assertRedirects(response, '/giris/?next=/makaleler/yeni/')
def test_create_logged_in(self):
self.client.login(username='ali', password='pass')
response = self.client.get('/makaleler/yeni/')
self.assertEqual(response.status_code, 200)
9. URL Yapısı Karşılaştırması
urlpatterns = [
# FBV
path('yeni/', views.article_create, name='article_create'),
# CBV — .as_view() zorunlu
path('', ArticleListView.as_view(), name='article_list'),
path('/', ArticleDetailView.as_view(), name='article_detail'),
path('/sil/', ArticleDeleteView.as_view(), name='article_delete'),
]
Özet
Her iki yaklaşımı da bilin ve duruma göre seçin. CBV: standart CRUD, tekrar eden kalıplar, mixin gereksinimi. FBV: karmaşık iş mantığı, webhook, tek işlevli view. Mixin kullanırken MRO sırasına dikkat edin — LoginRequiredMixin daima birinci. Test yazımı her iki yaklaşımda da benzer kolaylıkta.

Sıkça Sorulan Sorular
Mixin sırası neden önemli? expand_more
CBV'yi nasıl debug ederim? expand_more
CreateView'da form alanlarını özelleştirmek için ne yapmalıyım? expand_more
ViewSet ne zaman tercih edilmeli? expand_more
FBV vs CBV hangisi daha hızlı çalışır? expand_more
CBV ile TemplateView farkı nedir? expand_more
permission_required nasıl CBV'de kullanılır? expand_more
Ali Kasımoğlu
Full-stack Geliştirici & AnomixLabs Kurucusu
Python ve Django ekosisteminde uzmanlaşmış bir yazılım geliştirici. Modern web mimarileri, yapay zeka entegrasyonları ve minimalist kullanıcı deneyimleri üzerine odaklanıyor. AnomixLabs çatısı altında, karmaşık problemleri yalın ve etkili dijital çözümlere dönüştürmeyi hedefliyor.