Django Mülakat Soruları: ORM, Middleware ve DRF Derinlemesine İnceleme
Django mülakat soruları: select_related ve prefetch_related ile ORM optimizasyonu, middleware mimarisi ve Django REST Framework serializer performansı, izinler ve sayfalama kalıpları.

Django mülakat soruları, kıdemli adayları diğer adaylardan ayıran üç temel alan üzerinde yoğunlaşır: ORM hakimiyeti, middleware mimarisi ve Django REST Framework (DRF) tasarım kalıpları. Bu rehber, 2026 yılında işe alım yöneticilerinin sorduğu soruları Django 5.2 LTS ve DRF 3.17 ile üretim ortamına hazır kod örnekleriyle detaylı şekilde incelemektedir.
Django mülakatlarında temel CRUD işlemleri nadiren sorulur. Odak noktası QuerySet optimizasyonu (select_related ve prefetch_related farkı), özel middleware tasarımı ve DRF serializer performansına kaymıştır. N+1 sorgu sorununu açıklayabilen ve verimli ViewSet'ler yazabilen adaylar, yalnızca generic view'ları bilen adaylara kıyasla belirgin bir üstünlük sağlar.
Django ORM Mülakat Soruları: QuerySet Optimizasyonu
En sık sorulan Django ORM mülakat sorusu N+1 problemini hedef alır. Foreign key ilişkileri içeren bir model verildiğinde, adayların select_related ile prefetch_related arasındaki farkı ve her birinin ne zaman kullanılacağını göstermesi beklenir.
# models.py
from django.db import models
class Company(models.Model):
name = models.CharField(max_length=200)
founded_year = models.IntegerField()
class Developer(models.Model):
name = models.CharField(max_length=200)
company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name="developers")
skills = models.ManyToManyField("Skill", related_name="developers")
class Skill(models.Model):
name = models.CharField(max_length=100)
category = models.CharField(max_length=50)Bu iki yöntem arasındaki temel fark, geçilen ilişki türüne bağlıdır.
# queries.py — Correct approach for ForeignKey (single object)
developers = Developer.objects.select_related("company").all()
# Generates ONE SQL query with JOIN
# SELECT developer.*, company.* FROM developer INNER JOIN company ...
# Correct approach for ManyToMany (multiple objects)
developers = Developer.objects.prefetch_related("skills").all()
# Generates TWO SQL queries:
# 1. SELECT * FROM developer
# 2. SELECT * FROM skill INNER JOIN developer_skills WHERE developer_id IN (...)select_related bir SQL JOIN işlemi gerçekleştirir ve ForeignKey ile OneToOneField ilişkileriyle çalışır. prefetch_related ise ayrı bir sorgu çalıştırır ve ManyToManyField ile ters ForeignKey ilişkileri için uygundur. Bu ikisinin karıştırılması, büyük veri kümelerinde gereksiz JOIN'lere ya da N+1 sorununa yol açar.
İleri Düzey ORM: Özel Manager'lar ve QuerySet Zincirleme
Mülakatçılar genellikle adaylardan iş mantığı içeren bir özel manager yazmasını ister. Amaç, adayın Django'nun manager desenini anlayıp anlamadığını ve yeniden kullanılabilir sorgu arayüzleri yazıp yazamadığını doğrulamaktır.
# managers.py
from django.db import models
from django.utils import timezone
class ActiveDeveloperQuerySet(models.QuerySet):
def active(self):
"""Filter developers who logged in within the last 30 days."""
cutoff = timezone.now() - timezone.timedelta(days=30)
return self.filter(last_login__gte=cutoff)
def senior(self):
"""Filter developers with 5+ years of experience."""
return self.filter(years_experience__gte=5)
def by_skill(self, skill_name):
"""Filter developers by a specific skill."""
return self.filter(skills__name=skill_name)
class ActiveDeveloperManager(models.Manager):
def get_queryset(self):
return ActiveDeveloperQuerySet(self.model, using=self._db)
def active(self):
return self.get_queryset().active()Kilit takip sorusu genellikle şudur: "Neden sadece Manager yerine özel bir QuerySet kullanılmalı?" Cevap zincirleme yeteneğidir. Özel QuerySet metotları birbirine zincirlenebilirken, Manager metotları ilk çağrı sonrası zincirlenemez.
# usage.py — QuerySet chaining in action
# This works because each method returns a QuerySet
senior_python_devs = (
Developer.active_objects # custom manager
.active() # ActiveDeveloperQuerySet method
.senior() # chains another QuerySet method
.by_skill("Python") # chains a third method
.select_related("company") # standard QuerySet method still works
)Django 5.2, çok sütunlu birincil anahtarlara ihtiyaç duyan modeller için uzun süredir beklenen CompositePrimaryKey özelliğini sunmuştur. Bu özellikle ilgili mülakat soruları, özellikle eski veritabanları veya veri ambarı şemalarıyla çalışan adaylar için giderek yaygınlaşmaktadır.
Django Middleware Mülakat Soruları: İstek-Yanıt Boru Hattı
Middleware soruları, bir adayın Django'nun istek-yanıt yaşam döngüsünü ne kadar iyi anladığını ölçer. Standart soru şudur: "Bir middleware'in isteği ve yanıtı işleme sırasını açıklayınız."
Cevap belirli bir kalıp izler. İstek sırasında middleware sınıfları MIDDLEWARE ayarındaki sıralama ile yukarıdan aşağıya doğru çalışır. Yanıt sırasında ise aşağıdan yukarıya doğru çalışır. Bu soğan katmanı mimarisi, listedeki ilk middleware'in tüm işlem akışını sarmaladığı anlamına gelir.
# middleware.py
import time
import logging
from django.http import JsonResponse
logger = logging.getLogger(__name__)
class RequestTimingMiddleware:
"""Logs the time taken to process each request."""
def __init__(self, get_response):
self.get_response = get_response # next middleware or view
def __call__(self, request):
start_time = time.monotonic()
response = self.get_response(request) # passes to next layer
duration_ms = (time.monotonic() - start_time) * 1000
logger.info(
"method=%s path=%s status=%d duration=%.2fms",
request.method,
request.path,
response.status_code,
duration_ms,
)
return responseSık sorulan bir takip sorusu: "Middleware zinciri nasıl kısa devre yaptırılır?" __call__ içinde self.get_response(request) çağrılmadan önce bir HttpResponse döndürülmesi zinciri tamamen durdurur. Geri kalan middleware'ler ve view hiçbir zaman çalıştırılmaz.
# middleware.py — Rate limiting with short-circuit
from django.core.cache import cache
class RateLimitMiddleware:
"""Blocks requests exceeding 100 per minute per IP."""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
ip = request.META.get("REMOTE_ADDR")
cache_key = f"rate_limit:{ip}"
request_count = cache.get(cache_key, 0)
if request_count >= 100:
return JsonResponse( # short-circuits — view never executes
{"error": "Rate limit exceeded. Try again in 60 seconds."},
status=429,
)
cache.set(cache_key, request_count + 1, timeout=60)
return self.get_response(request)Middleware Hook'ları: process_view, process_exception ve process_template_response
__call__ dışında Django middleware'i üç opsiyonel hook metodunu destekler. Mülakatçılar bu konuyu adayın bilgi derinliğini ölçmek için kullanır.
# middleware.py — Full middleware with all hooks
class AuditMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
return self.get_response(request)
def process_view(self, request, view_func, view_args, view_kwargs):
"""Called after URL resolution, before the view executes."""
logger.info("Calling view: %s", view_func.__name__)
return None # returning None continues normal processing
def process_exception(self, request, exception):
"""Called only if the view raises an exception."""
logger.error("View exception: %s", exception, exc_info=True)
return None # returning None lets Django's default handling proceed
def process_template_response(self, request, response):
"""Called if the response has a render() method (TemplateResponse)."""
response.context_data["audit_timestamp"] = time.time()
return response # must return a response with render()process_view, URL çözümlemesinden sonra ancak view çalıştırılmadan önce tetiklenir. None döndürülmesi işlemin devam etmesini sağlar; bir HttpResponse döndürülmesi ise kısa devre oluşturur. process_exception yalnızca yakalanmamış istisnalarda devreye girer. process_template_response ise yalnızca TemplateResponse nesneleri için çalışır, normal HttpResponse için çalışmaz.
Django mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
DRF Mülakat Soruları: Serializer Performansı
Django REST Framework serializer soruları, iç içe serileştirme ve farklı yaklaşımların performans üzerindeki etkilerine odaklanır. En çok sorulan soru şudur: "N+1 sorgu sorununa yol açmadan iç içe ilişkiler nasıl yönetilir?"
# serializers.py
from rest_framework import serializers
from .models import Developer, Company, Skill
class SkillSerializer(serializers.ModelSerializer):
class Meta:
model = Skill
fields = ["name", "category"]
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ["name", "founded_year"]
class DeveloperSerializer(serializers.ModelSerializer):
company = CompanySerializer(read_only=True) # nested FK
skills = SkillSerializer(many=True, read_only=True) # nested M2M
class Meta:
model = Developer
fields = ["id", "name", "company", "skills"]Serializer tek başına performans sorununu çözmez. ViewSet'in queryset'i optimize etmesi gerekir.
# views.py
from rest_framework import viewsets
from .models import Developer
from .serializers import DeveloperSerializer
class DeveloperViewSet(viewsets.ReadOnlyModelViewSet):
serializer_class = DeveloperSerializer
def get_queryset(self):
return (
Developer.objects
.select_related("company") # JOIN for FK
.prefetch_related("skills") # separate query for M2M
.order_by("-id")
)ViewSet'te select_related ve prefetch_related kullanılmadan, her bir serialize edilen Developer nesnesi için company ve skills bağımsız sorgular tetiklenir. 50 geliştiriciden oluşan bir listede bu, 3 yerine 1 + 50 + 50 = 101 sorgu anlamına gelir.
DRF Özel İzinler ve Kimlik Doğrulama
Sık sorulan bir DRF mülakat sorusu: "Kullanıcının rolüne ve nesnenin sahibine göre erişimi kısıtlayan özel bir izin sınıfı yazınız."
# permissions.py
from rest_framework.permissions import BasePermission
class IsOwnerOrAdmin(BasePermission):
"""
Object-level permission:
- Admin users can access any object
- Regular users can only access objects they own
"""
message = "Access restricted to the object owner or admin users."
def has_object_permission(self, request, view, obj):
if request.user.is_staff:
return True
# Assumes the model has an 'owner' field pointing to User
return obj.owner == request.user# views.py — Applying custom permissions
from rest_framework import viewsets, permissions
from .permissions import IsOwnerOrAdmin
class ProjectViewSet(viewsets.ModelViewSet):
permission_classes = [permissions.IsAuthenticated, IsOwnerOrAdmin]
def get_queryset(self):
# Non-admin users only see their own projects
if self.request.user.is_staff:
return Project.objects.all()
return Project.objects.filter(owner=self.request.user)
def perform_create(self, serializer):
serializer.save(owner=self.request.user) # auto-assign ownerMülakatçıların aradığı kilit nüans şudur: has_permission her istekte çalışır (liste düzeyinde), has_object_permission ise yalnızca get_object() çağrıldığında çalışır (detay düzeyinde). List view'larda get_queryset metodu override edilmezse, kullanıcıların sahip olmadıkları nesneleri görebileceği bir güvenlik açığı oluşur.
Yalnızca has_object_permission'a güvenip queryset'i filtrelememek, list endpoint'ini korumasız bırakır. Erişim kontrolünü hem liste hem de detay görünümlerinde uygulamak için nesne düzeyindeki izinleri her zaman filtrelenmiş bir get_queryset ile birleştirmek gerekir.
DRF Hız Sınırlandırma ve Sayfalama Kalıpları
Hız sınırlandırma (throttling) ve sayfalama (pagination) standart takip sorularıdır. Mülakatçılar, adayların üretim ortamına uygun API yapılandırmasını anlayıp anlamadığını görmek ister.
# settings.py — Production DRF configuration
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": [
"rest_framework.throttling.AnonRateThrottle",
"rest_framework.throttling.UserRateThrottle",
],
"DEFAULT_THROTTLE_RATES": {
"anon": "20/minute", # unauthenticated users
"user": "200/minute", # authenticated users
},
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.CursorPagination",
"PAGE_SIZE": 25,
}# pagination.py — Custom cursor pagination for consistent ordering
from rest_framework.pagination import CursorPagination
class CreatedAtCursorPagination(CursorPagination):
page_size = 25
ordering = "-created_at" # must be a unique, sequential field
cursor_query_param = "cursor" # ?cursor=abc123Cursor tabanlı sayfalama, büyük veri kümelerinde offset tabanlı sayfalamadan daha iyi performans gösterir; çünkü toplam satır sayısını saymaya ihtiyaç duymaz. Ödenmesi gereken bedel: istemciler rastgele sayfalara atlayamaz. Mülakatçıların "Sayfa numarası tabanlı sayfalama yerine neden cursor sayfalama tercih edersiniz?" sorusuna beklenen cevap tam olarak budur.
Sonuç
Django mülakat hazırlığında anahtar çıkarımlar:
- ORM optimizasyonu: Sorgu yöntemi her zaman ilişki türüne uygun seçilmelidir. ForeignKey ve OneToOne için
select_related, ManyToMany ve ters FK içinprefetch_relatedkullanılır. Özel QuerySet'ler zincirlenebilir ve yeniden kullanılabilir iş mantığı sağlar. - Middleware mimarisi: İstek yukarıdan aşağıya, yanıt aşağıdan yukarıya akar.
get_response()çağrılmadan önce yanıt döndürerek kısa devre yapmak, hız sınırlandırma, kimlik doğrulama kontrolleri ve istek doğrulama için temel bir desendir. - DRF serializer performansı: İç içe serializer'lar, ViewSet'te açık queryset optimizasyonu gerektirir.
select_relatedveprefetch_relatedolmadan serileştirme, büyük ölçekte N+1 sorgularına neden olur. - DRF izinleri: Erişim kontrolünü hem liste hem de detay endpoint'lerinde uygulamak için
has_object_permissionile filtrelenmiş birget_querysetbirleştirilmelidir. Nesne düzeyindeki izinler tek başına liste görünümlerini korumasız bırakır. - Hız sınırlandırma ve sayfalama: Cursor sayfalama büyük tablolarda offset'e göre daha iyi ölçeklenir. Anonim ve kimlik doğrulanmış kullanıcılar için hız sınırları ayrı ayrı yapılandırılmalıdır.
Django ORM mülakat sorularını ve middleware sorularını SharpSkill üzerinde pratik yaparak gerçek mülakat öncesinde özgüven kazanmak mümkündür.
Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Etiketler
Paylaş
İlgili makaleler

Django 5.2 Middleware ve Signal Mekanizmalari: Teknik Mulakat Rehberi
Django 5.2'de custom middleware yazimi, signal handling, post_save, pre_save, async middleware ve domain olaylari. Teknik mulakat sorularina yonelik kapsamli rehber ve Python kod ornekleri.

Django ve Python Mulakat Sorulari: 2026'nin En Onemli 25 Sorusu
Django ve Python mulakatlarinda en sik sorulan 25 soru. ORM, gorunumler, middleware, DRF, sinyaller ve optimizasyon detayli cevaplar ve kod ornekleriyle.

Django ve Celery: Asenkron Görev İşleme ve Mülakat Soruları 2026
Django ve Celery entegrasyonu, asenkron görev işleme, kuyruk yönetimi, Celery Beat zamanlayıcı ve üretim yapılandırması. 2026 mülakat soruları dahil.