Giris
Django REST Framework (DRF), Django uzerinde JSON/XML API'ler insa etmek icin endustri standardi bir arac setidir. Serializer katmani veri donusumu ve validasyonu, View/ViewSet katmani HTTP semantigini, permission ve throttle katmanlari guvenligi yonetir.
Bu yazida temel Serializer'dan ModelViewSet'e kadar ilerleyerek tam bir blog API'si ornegi kuracagiz. Nested serializer, custom validation ve pagination gibi gercek dunya ihtiyaclarini ele alacagiz.
Serializer Temelleri
Serializer, Python nesnelerini JSON'a ve tersine cevirir. is_valid() cagrisi validation calistirir; validated_data temiz girdiyi icerir. read_only ve write_only alanlar API sozlesmesini netlestirir.
- serializer.data: serialize edilmis cikti
- serializer.save(): create/update hook'lari
- to_representation() ile custom cikti formati
from rest_framework import serializers
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
body = serializers.CharField(max_length=1000)
def validate_body(self, value):
if len(value.strip()) < 10:
raise serializers.ValidationError('Yorum en az 10 karakter olmali.')
return valueModelSerializer ve Iliskiler
ModelSerializer, Model meta verisinden otomatik alan uretir. PrimaryKeyRelatedField ve nested serializer ile ForeignKey/ManyToMany iliskileri expose edilir. depth parametresi hizli prototipleme icin kullanilir ancak uretimde kontrol kaybina yol acar.
class PostSerializer(serializers.ModelSerializer):
author_name = serializers.CharField(source='author.username', read_only=True)
tags = serializers.SlugRelatedField(
many=True, slug_field='name', queryset=Tag.objects.all()
)
class Meta:
model = Post
fields = ['id', 'title', 'slug', 'body', 'author_name', 'tags']
read_only_fields = ['id', 'slug']APIView ve Generic View
APIView her HTTP metodu icin ayri handler saglar. Generic view'lar ListCreateAPIView gibi hazir kaliplar sunar. Performans icin queryset uzerinde select_related kullanmayi unutmayin.
from rest_framework import generics, permissions
class PostListCreateAPIView(generics.ListCreateAPIView):
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def get_queryset(self):
return Post.objects.select_related('author').prefetch_related('tags')Her endpoint icin queryset'i view'da tanimlayin; serializer veri sekline, view erisim kurallarina sahip olsun.
ViewSet ve Router
ViewSet, CRUD aksiyonlarini tek sinifta toplar: list, retrieve, create, update, destroy. DefaultRouter otomatik URL uretir. @action decorator ile ozel endpoint eklenebilir.
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.select_related('author')
serializer_class = PostSerializer
lookup_field = 'slug'
@action(detail=True, methods=['post'])
def publish(self, request, slug=None):
post = self.get_object()
post.publish()
return Response({'status': 'published'})Permission, Pagination ve Filtering
IsAuthenticated, DjangoModelPermissions ve custom permission siniflari erisim kontrolu saglar. PageNumberPagination ile sayfalama standartlastirilir. django-filter entegrasyonu ile query param filtreleme eklenir.
- permission_classes view veya ViewSet seviyesinde
- throttle_classes rate limiting icin
- renderer_classes JSON disinda format destegi
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
],
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
],
}Hata Yonetimi ve Test
DRF tutarli hata formati doner: {'field': ['mesaj']}. APIClient ile entegrasyon testleri yazilir. force_authenticate ile auth durumu simule edilir.
- Serializer unit test: is_valid() ve validate_* metodlari
- APITestCase ile HTTP status ve payload
- Factory pattern ile test verisi
from rest_framework.test import APITestCase
class PostAPITest(APITestCase):
def test_create_requires_auth(self):
response = self.client.post('/api/posts/', {'title': 'Test'})
self.assertEqual(response.status_code, 401)Sonuc
DRF ile API gelistirmek Django'nun ORM ve auth altyapisini bozmadan olceklenebilir servisler uretmenizi saglar. ViewSet + Router kombinasyonu CRUD projelerinde hiz kazandirir; karmasik is akislari icin APIView veya custom action tercih edin.
- Nested serializer'da N+1'e dikkat (prefetch_related)
- Versiyonlama icin namespace veya URL prefix
- OpenAPI schema: drf-spectacular kullanin