{"id":31772,"date":"2025-10-13T21:02:13","date_gmt":"2025-10-13T18:02:13","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/"},"modified":"2025-10-13T21:02:13","modified_gmt":"2025-10-13T18:02:13","slug":"django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/","title":{"rendered":"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler"},"content":{"rendered":"<p><body><\/p>\n<p>Bir Django projesinde Class-Based Views (CBV) kullanarak verimli ve \u00f6l\u00e7eklenebilir API&#8217;ler nas\u0131l olu\u015fturulur? Frontend ile sorunsuz entegrasyon i\u00e7in ad\u0131m ad\u0131m rehberimizle ke\u015ffedin, modern web uygulamalar\u0131n\u0131z i\u00e7in g\u00fc\u00e7l\u00fc backend \u00e7\u00f6z\u00fcmleri geli\u015ftirin.<\/p>\n<p>Modern web geli\u015ftirme d\u00fcnyas\u0131nda, kullan\u0131c\u0131 deneyimi hi\u00e7 bu kadar \u00f6nemli olmam\u0131\u015ft\u0131. Tek Sayfa Uygulamalar\u0131 (SPA&#8217;lar) ve mobil uygulamalar gibi dinamik aray\u00fczler, geleneksel sunucu tarafl\u0131 render edilmi\u015f sayfalar\u0131n \u00f6tesine ge\u00e7erek kesintisiz ve etkile\u015fimli bir deneyim sunma ihtiyac\u0131n\u0131 do\u011furdu. Peki, Django gibi g\u00fc\u00e7l\u00fc bir web \u00e7at\u0131s\u0131 kullan\u0131rken, bu modern frontend uygulamalar\u0131na nas\u0131l veri sa\u011flayabiliriz? \u0130\u015fte tam bu noktada, Application Programming Interface (API) kavram\u0131 devreye giriyor ve adeta bir k\u00f6pr\u00fc g\u00f6revi \u00fcstleniyor. Geleneksel Django projelerinde, veritaban\u0131ndan al\u0131nan veriler genellikle Django \u015fablonlar\u0131 arac\u0131l\u0131\u011f\u0131yla HTML&#8217;e d\u00f6n\u00fc\u015ft\u00fcr\u00fcl\u00fcp do\u011frudan taray\u0131c\u0131ya g\u00f6nderilir. Ancak, React, Vue.js, Angular gibi JavaScript \u00e7er\u00e7eveleri veya native mobil uygulamalar, kendi kullan\u0131c\u0131 aray\u00fczlerini olu\u015fturur ve sadece ham veri format\u0131na ihtiya\u00e7 duyar.<\/p>\n<p>Bir API, backend&#8217;iniz ile frontend&#8217;iniz aras\u0131nda bir s\u00f6zle\u015fme gibidir. Frontend, belirli bir URL&#8217;ye (endpoint) HTTP istekleri g\u00f6ndererek veri talep eder veya veri g\u00f6nderir. Backend ise bu istekleri i\u015fler, veritaban\u0131 ile etkile\u015fime girer ve genellikle JSON (JavaScript Object Notation) format\u0131nda standartla\u015ft\u0131r\u0131lm\u0131\u015f bir yan\u0131t d\u00f6ner. Bu yakla\u015f\u0131m, &#8220;sorumluluklar\u0131n ayr\u0131lmas\u0131&#8221; prensibini destekler: frontend sadece kullan\u0131c\u0131 aray\u00fcz\u00fc ve kullan\u0131c\u0131 etkile\u015fimleriyle ilgilenirken, backend veri y\u00f6netimi, i\u015f mant\u0131\u011f\u0131 ve g\u00fcvenlik gibi konulara odaklan\u0131r. Bu ayr\u0131m, geli\u015ftirme s\u00fcre\u00e7lerini h\u0131zland\u0131r\u0131r, kod taban\u0131n\u0131 daha y\u00f6netilebilir hale getirir ve ekiplerin paralel \u00e7al\u0131\u015fmas\u0131na olanak tan\u0131r. \u00d6rne\u011fin, bir e-ticaret uygulamas\u0131nda, \u00fcr\u00fcn listesi, sepete ekleme, sipari\u015f tamamlama gibi t\u00fcm i\u015flemler bir API arac\u0131l\u0131\u011f\u0131yla ger\u00e7ekle\u015ftirilebilir. Mobil uygulama geli\u015ftiricileri ve web frontend geli\u015ftiricileri ayn\u0131 API&#8217;yi kullanarak tutarl\u0131 bir veri ak\u0131\u015f\u0131na sahip olurlar. Bu esneklik ve \u00f6l\u00e7eklenebilirlik, g\u00fcn\u00fcm\u00fcz\u00fcn h\u0131zla de\u011fi\u015fen dijital ortam\u0131nda kritik bir avantajd\u0131r. Django&#8217;nun Class-Based Views (CBV) yap\u0131s\u0131, bu t\u00fcr API&#8217;leri olu\u015fturmak i\u00e7in bize hem g\u00fc\u00e7l\u00fc hem de esnek bir temel sunar. Genellikle Django REST Framework (DRF) API geli\u015ftirme i\u00e7in pop\u00fcler bir se\u00e7im olsa da, Django&#8217;nun kendi CBV&#8217;leri ile de olduk\u00e7a yetenekli ve \u00f6zelle\u015ftirilebilir API&#8217;ler in\u015fa edebiliriz, \u00f6zellikle projemizin ihtiya\u00e7lar\u0131 DRF&#8217;nin t\u00fcm \u00f6zelliklerini gerektirmedi\u011finde.<\/p>\n<h2>Django Class-Based Views (CBV) Nedir ve Neden Kullanmal\u0131y\u0131z?<\/h2>\n<p>Django, geleneksel olarak &#8220;Function-Based Views&#8221; (FBV) yani fonksiyon tabanl\u0131 g\u00f6r\u00fcn\u00fcmlerle bilinse de, 1.3 s\u00fcr\u00fcm\u00fcnden itibaren &#8220;Class-Based Views&#8221; (CBV) yani s\u0131n\u0131f tabanl\u0131 g\u00f6r\u00fcn\u00fcmleri de desteklemeye ba\u015flam\u0131\u015ft\u0131r. Peki, bu iki yakla\u015f\u0131m aras\u0131ndaki fark nedir ve neden CBV&#8217;leri tercih etmeliyiz? Fonksiyon tabanl\u0131 g\u00f6r\u00fcn\u00fcmler, her HTTP iste\u011fini (GET, POST, PUT, DELETE vb.) bir if-elif-else blo\u011fu i\u00e7inde kontrol eden ve belirli bir g\u00f6revi yerine getiren basit Python fonksiyonlar\u0131d\u0131r. B\u00fcy\u00fck \u00f6l\u00e7\u00fcde esneklik sunsalar da, karma\u015f\u0131k uygulamalarda kod tekrar\u0131na, mant\u0131ksal kar\u0131\u015f\u0131kl\u0131\u011fa ve okunabilirli\u011fin azalmas\u0131na yol a\u00e7abilirler. \u00d6rne\u011fin, bir modelin listesini ve detay\u0131n\u0131 g\u00f6steren iki ayr\u0131 fonksiyon yazman\u0131z gerekebilir ve bu fonksiyonlar benzer kod par\u00e7ac\u0131klar\u0131 i\u00e7erebilir.<\/p>\n<p>CBV&#8217;ler ise, ad\u0131ndan da anla\u015f\u0131laca\u011f\u0131 \u00fczere Python s\u0131n\u0131flar\u0131d\u0131r. Her bir HTTP metodu i\u00e7in ayr\u0131 bir s\u0131n\u0131f metodu tan\u0131mlayarak (\u00f6rne\u011fin, <code>get()<\/code>, <code>post()<\/code>, <code>put()<\/code>, <code>delete()<\/code>), gelen iste\u011fi daha organize bir \u015fekilde ele almam\u0131z\u0131 sa\u011flarlar. CBV&#8217;lerin sundu\u011fu en b\u00fcy\u00fck avantajlardan biri, &#8220;kal\u0131t\u0131m&#8221; ve &#8220;mixin&#8221; mimarileridir. Django&#8217;nun kendi b\u00fcnyesinde gelen <code>View<\/code>, <code>TemplateView<\/code>, <code>ListView<\/code>, <code>DetailView<\/code> gibi genel CBV&#8217;leri, belirli g\u00f6revler i\u00e7in \u00f6nceden tan\u0131mlanm\u0131\u015f \u015fablonlar sunar. Bu genel g\u00f6r\u00fcn\u00fcmlerden t\u00fcreterek veya mixin&#8217;ler ekleyerek kendi \u00f6zel g\u00f6r\u00fcn\u00fcmlerimizi \u00e7ok daha az kodla ve daha mod\u00fcler bir yap\u0131da olu\u015fturabiliriz. \u00d6rne\u011fin, bir veri listesini g\u00f6stermek i\u00e7in <code>ListView<\/code>&#8216;i, tek bir \u00f6\u011fenin detay\u0131n\u0131 g\u00f6stermek i\u00e7in ise <code>DetailView<\/code>&#8216;i kullanabiliriz. Bu s\u0131n\u0131flar, varsay\u0131lan olarak bir \u015fablon render etme davran\u0131\u015f\u0131na sahip olsalar da, biz bunlar\u0131 API ba\u011flam\u0131nda JSON yan\u0131tlar\u0131 d\u00f6nd\u00fcrecek \u015fekilde kolayca \u00f6zelle\u015ftirebiliriz.<\/p>\n<p>CBV&#8217;lerin sundu\u011fu di\u011fer \u00f6nemli faydalar \u015funlard\u0131r:<\/p>\n<ul>\n<li><strong>Kod Tekrar\u0131n\u0131 Azaltma:<\/strong> Ortak mant\u0131k, temel s\u0131n\u0131flarda veya mixin&#8217;lerde tan\u0131mlanabilir ve farkl\u0131 g\u00f6r\u00fcn\u00fcmler taraf\u0131ndan yeniden kullan\u0131labilir. Bu, &#8220;Don&#8217;t Repeat Yourself&#8221; (DRY) prensibine m\u00fckemmel bir \u015fekilde uyar.<\/li>\n<li><strong>Okunabilirlik ve Bak\u0131m Kolayl\u0131\u011f\u0131:<\/strong> Her HTTP metodunun kendi metoduna sahip olmas\u0131, kodun ne yapt\u0131\u011f\u0131n\u0131 anlamay\u0131 kolayla\u015ft\u0131r\u0131r. Yeni bir \u00f6zellik eklendi\u011finde veya mevcut bir \u00f6zellik de\u011fi\u015ftirildi\u011finde, ilgili kodu bulmak ve g\u00fcncellemek daha basittir.<\/li>\n<li><strong>Geni\u015fletilebilirlik:<\/strong> Kal\u0131t\u0131m yoluyla veya mixin&#8217;ler kullanarak, varolan CBV&#8217;leri kolayca geni\u015fletebilir ve projenizin \u00f6zel ihtiya\u00e7lar\u0131na g\u00f6re uyarlayabilirsiniz. Bu, \u00f6zellikle karma\u015f\u0131k API&#8217;ler geli\u015ftirirken b\u00fcy\u00fck bir esneklik sa\u011flar.<\/li>\n<li><strong>Method Resolution Order (MRO):<\/strong> Python&#8217;\u0131n g\u00fc\u00e7l\u00fc MRO mekanizmas\u0131 sayesinde, \u00e7oklu kal\u0131t\u0131m ve mixin kullan\u0131m\u0131nda metotlar\u0131n hangi s\u0131rayla \u00e7a\u011fr\u0131laca\u011f\u0131 belirli bir kurala tabidir, bu da beklenmedik davran\u0131\u015flar\u0131n \u00f6n\u00fcne ge\u00e7er.<\/li>\n<\/ul>\n<p>\u00d6zetle, CBV&#8217;ler, Django projelerinizde daha d\u00fczenli, \u00f6l\u00e7eklenebilir ve s\u00fcrd\u00fcr\u00fclebilir bir kod taban\u0131 olu\u015fturman\u0131za olanak tan\u0131r. \u00d6zellikle API geli\u015ftirirken, farkl\u0131 HTTP metotlar\u0131n\u0131 y\u00f6netme ve veri serile\u015ftirme gibi tekrarlayan g\u00f6revler i\u00e7in CBV&#8217;lerin sa\u011flad\u0131\u011f\u0131 yap\u0131sal avantajlar paha bi\u00e7ilmezdir. Dolay\u0131s\u0131yla, modern web uygulamalar\u0131 i\u00e7in API&#8217;ler olu\u015ftururken CBV&#8217;leri benimsemek, geli\u015ftirme s\u00fcrecinizi \u00f6nemli \u00f6l\u00e7\u00fcde iyile\u015ftirecektir.<\/p>\n<h3>Basit Bir RESTful API Olu\u015fturmaya Nas\u0131l Ba\u015flars\u0131n\u0131z?<\/h3>\n<p>\u015eimdi teoriden prati\u011fe ge\u00e7elim ve Django CBV&#8217;lerini kullanarak basit bir RESTful API&#8217;yi nas\u0131l ad\u0131m ad\u0131m olu\u015fturaca\u011f\u0131m\u0131za bakal\u0131m. Bu \u00f6rnekte, basit bir \u00fcr\u00fcn listesini ve detaylar\u0131n\u0131 d\u00f6nd\u00fcren bir API geli\u015ftirece\u011fiz. Temel amac\u0131m\u0131z, Django&#8217;nun <code>JsonResponse<\/code> s\u0131n\u0131f\u0131n\u0131 kullanarak JSON format\u0131nda yan\u0131tlar \u00fcretmek ve CBV&#8217;lerin temelini anlamak.<\/p>\n<h4>1. Proje ve Uygulama Yap\u0131land\u0131rmas\u0131<\/h4>\n<p>\u00d6ncelikle bir Django projesi ve API&#8217;mizi bar\u0131nd\u0131racak bir uygulama olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-bash\">\ndjango-admin startproject myapi_project\ncd myapi_project\npython manage.py startapp products_api\n<\/pre>\n<p><\/code><\/p>\n<p>Ard\u0131ndan, <code>myapi_project\/settings.py<\/code> dosyan\u0131za <code>products_api<\/code> uygulamas\u0131n\u0131 eklemeyi unutmay\u0131n:<\/p>\n<pre><code class=\"language-python\">\n# myapi_project\/settings.py\nINSTALLED_APPS = [\n    # ... di\u011fer uygulamalar\n    'products_api',\n]\n<\/pre>\n<p><\/code><\/p>\n<h4>2. Model Tan\u0131mlamas\u0131<\/h4>\n<p>API'mizin temelini olu\u015fturacak basit bir <code>Product<\/code> modeli tan\u0131mlayal\u0131m. Bu model, \u00fcr\u00fcn ad\u0131, a\u00e7\u0131klama ve fiyat gibi alanlara sahip olacak. Bu, veritaban\u0131m\u0131zda saklayaca\u011f\u0131m\u0131z verilerin yap\u0131s\u0131n\u0131 belirleyecektir.<\/p>\n<pre><code class=\"language-python\">\n# products_api\/models.py\nfrom django.db import models\n\nclass Product(models.Model):\n    name = models.CharField(max_length=100)\n    description = models.TextField()\n    price = models.DecimalField(max_digits=10, decimal_places=2)\n    created_at = models.DateTimeField(auto_now_add=True)\n    updated_at = models.DateTimeField(auto_now=True)\n\n    def __str__(self):\n        return self.name\n\n    class Meta:\n        ordering = ['name']\n<\/pre>\n<p><\/code><\/p>\n<p>Modeli tan\u0131mlad\u0131ktan sonra, veritaban\u0131 ge\u00e7i\u015flerini (migrations) \u00e7al\u0131\u015ft\u0131ral\u0131m:<\/p>\n<pre><code class=\"language-bash\">\npython manage.py makemigrations products_api\npython manage.py migrate\n<\/pre>\n<p><\/code><\/p>\n<p>Daha sonra baz\u0131 test verileri eklemek i\u00e7in bir s\u00fcper kullan\u0131c\u0131 olu\u015fturabilirsiniz: <code>python manage.py createsuperuser<\/code>.<\/p>\n<h4>3. Temel CBV ile API G\u00f6r\u00fcn\u00fcm\u00fc<\/h4>\n<p>\u015eimdi <code>products_api\/views.py<\/code> dosyam\u0131zda ilk API g\u00f6r\u00fcn\u00fcm\u00fcm\u00fcz\u00fc olu\u015ftural\u0131m. Burada <code>django.views.View<\/code> s\u0131n\u0131f\u0131n\u0131 kullanaca\u011f\u0131z. Bu, t\u00fcm genel CBV'lerin temelini olu\u015fturan en basit s\u0131n\u0131f tabanl\u0131 g\u00f6r\u00fcn\u00fcmd\u00fcr ve HTTP metotlar\u0131n\u0131 manuel olarak ele almam\u0131za olanak tan\u0131r. <code>GET<\/code> iste\u011fi i\u00e7in t\u00fcm \u00fcr\u00fcnleri listeleyece\u011fiz ve <code>POST<\/code> iste\u011fi i\u00e7in yeni bir \u00fcr\u00fcn olu\u015fturaca\u011f\u0131z.<\/p>\n<pre><code class=\"language-python\">\n# products_api\/views.py\nimport json\nfrom django.views import View\nfrom django.http import JsonResponse\nfrom django.forms.models import model_to_dict # Model nesnesini s\u00f6zl\u00fc\u011fe \u00e7evirmek i\u00e7in\n\nfrom .models import Product\n\nclass ProductListView(View):\n    def get(self, request, *args, **kwargs):\n        \"\"\"\n        T\u00fcm \u00fcr\u00fcnleri listeler.\n        \"\"\"\n        products = Product.objects.all()\n        # Her Product objesini bir s\u00f6zl\u00fc\u011fe \u00e7evirip bir liste olu\u015fturuyoruz.\n        # model_to_dict, basit modeller i\u00e7in h\u0131zl\u0131 bir serile\u015ftirme sa\u011flar.\n        # Daha karma\u015f\u0131k senaryolar i\u00e7in custom bir serializer yazmak daha iyidir.\n        data = [model_to_dict(p, fields=['id', 'name', 'description', 'price']) for p in products]\n        return JsonResponse(data, safe=False) # safe=False: Listenin do\u011frudan JSON'a \u00e7evrilmesine izin verir.\n\n    def post(self, request, *args, **kwargs):\n        \"\"\"\n        Yeni bir \u00fcr\u00fcn olu\u015fturur.\n        \"\"\"\n        try:\n            # Gelen iste\u011fin body'sini JSON olarak parse ediyoruz.\n            # request.body byte tipindedir, utf-8 ile decode etmeliyiz.\n            data = json.loads(request.body.decode('utf-8'))\n            name = data.get('name')\n            description = data.get('description')\n            price = data.get('price')\n\n            if not all([name, description, price]):\n                return JsonResponse({'error': 'Ad, a\u00e7\u0131klama ve fiyat alanlar\u0131 zorunludur.'}, status=400)\n\n            product = Product.objects.create(name=name, description=description, price=price)\n            # Olu\u015fturulan \u00fcr\u00fcn\u00fcn bilgilerini JSON olarak d\u00f6nd\u00fcr\u00fcyoruz.\n            return JsonResponse(model_to_dict(product, fields=['id', 'name', 'description', 'price']), status=201) # 201 Created\n        except json.JSONDecodeError:\n            return JsonResponse({'error': 'Ge\u00e7ersiz JSON format\u0131.'}, status=400)\n        except Exception as e:\n            return JsonResponse({'error': str(e)}, status=500)\n\nclass ProductDetailView(View):\n    def get(self, request, pk, *args, **kwargs):\n        \"\"\"\n        Belirli bir \u00fcr\u00fcn\u00fcn detay\u0131n\u0131 getirir.\n        \"\"\"\n        try:\n            product = Product.objects.get(pk=pk)\n            data = model_to_dict(product, fields=['id', 'name', 'description', 'price'])\n            return JsonResponse(data)\n        except Product.DoesNotExist:\n            return JsonResponse({'error': '\u00dcr\u00fcn bulunamad\u0131.'}, status=404)\n\n    def put(self, request, pk, *args, **kwargs):\n        \"\"\"\n        Belirli bir \u00fcr\u00fcn\u00fc g\u00fcnceller.\n        \"\"\"\n        try:\n            product = Product.objects.get(pk=pk)\n            data = json.loads(request.body.decode('utf-8'))\n\n            product.name = data.get('name', product.name)\n            product.description = data.get('description', product.description)\n            product.price = data.get('price', product.price)\n            product.save()\n\n            return JsonResponse(model_to_dict(product, fields=['id', 'name', 'description', 'price']))\n        except Product.DoesNotExist:\n            return JsonResponse({'error': '\u00dcr\u00fcn bulunamad\u0131.'}, status=404)\n        except json.JSONDecodeError:\n            return JsonResponse({'error': 'Ge\u00e7ersiz JSON format\u0131.'}, status=400)\n        except Exception as e:\n            return JsonResponse({'error': str(e)}, status=500)\n\n    def delete(self, request, pk, *args, **kwargs):\n        \"\"\"\n        Belirli bir \u00fcr\u00fcn\u00fc siler.\n        \"\"\"\n        try:\n            product = Product.objects.get(pk=pk)\n            product.delete()\n            return JsonResponse({'message': '\u00dcr\u00fcn ba\u015far\u0131yla silindi.'}, status=204) # 204 No Content\n        except Product.DoesNotExist:\n            return JsonResponse({'error': '\u00dcr\u00fcn bulunamad\u0131.'}, status=404)\n        except Exception as e:\n            return JsonResponse({'error': str(e)}, status=500)\n<\/pre>\n<p><\/code><\/p>\n<div class=\"expert-tip\">\n    Uzman \u0130pucu: <code>model_to_dict<\/code>, h\u0131zl\u0131 prototipleme i\u00e7in kullan\u0131\u015fl\u0131 olsa da, karma\u015f\u0131k serile\u015ftirme veya veri do\u011frulama ihtiya\u00e7lar\u0131n\u0131z oldu\u011funda kendi \u00f6zel serializer s\u0131n\u0131flar\u0131n\u0131z\u0131 (\u00f6rne\u011fin <code>django.forms.ModelForm<\/code>'dan t\u00fcretilmi\u015f) olu\u015fturman\u0131z veya Django REST Framework'\u00fcn serializer'lar\u0131n\u0131 kullanman\u0131z daha iyi bir yakla\u015f\u0131md\u0131r.\n<\/div>\n<h4>4. URL Yap\u0131land\u0131rmas\u0131<\/h4>\n<p>Son olarak, bu g\u00f6r\u00fcn\u00fcmleri URL'lere ba\u011flamam\u0131z gerekiyor. <code>products_api<\/code> uygulamam\u0131z\u0131n i\u00e7ine bir <code>urls.py<\/code> dosyas\u0131 olu\u015ftural\u0131m ve ana proje <code>urls.py<\/code> dosyam\u0131zdan bu dosyay\u0131 dahil edelim.<\/p>\n<pre><code class=\"language-python\">\n# products_api\/urls.py\nfrom django.urls import path\nfrom .views import ProductListView, ProductDetailView\n\nurlpatterns = [\n    path('products\/', ProductListView.as_view(), name='product-list'),\n    path('products\/<int:pk>\/', ProductDetailView.as_view(), name='product-detail'),\n]\n<\/pre>\n<p><\/code><\/p>\n<pre><code class=\"language-python\"><\/pre>\n<p><\/code><br \/>\n# myapi_project\/urls.py<br \/>\nfrom django.contrib import admin<br \/>\nfrom django.urls import path, include<\/p>\n<p>urlpatterns = [<br \/>\n    path('admin\/', admin.site.urls),<br \/>\n    path('api\/', include('products_api.urls')), # API URL'lerini dahil et<br \/>\n]<br \/>\n<\/code><\/p>\n<p>Art\u0131k Django sunucusunu \u00e7al\u0131\u015ft\u0131rarak (<code>python manage.py runserver<\/code>) API'nizi test edebilirsiniz:<\/p>\n<ul>\n<li><code>GET \/api\/products\/<\/code>: T\u00fcm \u00fcr\u00fcnleri listeler.<\/li>\n<li><code>POST \/api\/products\/<\/code>: Yeni \u00fcr\u00fcn olu\u015fturur (JSON body ile).<\/li>\n<li><code>GET \/api\/products\/1\/<\/code>: ID'si 1 olan \u00fcr\u00fcn\u00fcn detay\u0131n\u0131 getirir.<\/li>\n<li><code>PUT \/api\/products\/1\/<\/code>: ID'si 1 olan \u00fcr\u00fcn\u00fc g\u00fcnceller (JSON body ile).<\/li>\n<li><code>DELETE \/api\/products\/1\/<\/code>: ID'si 1 olan \u00fcr\u00fcn\u00fc siler.<\/li>\n<\/ul>\n<p>Bu ad\u0131mlar, Django CBV'lerini kullanarak nas\u0131l basit ve i\u015flevsel bir RESTful API olu\u015fturulaca\u011f\u0131n\u0131 g\u00f6stermektedir. Bu temel yap\u0131, daha karma\u015f\u0131k API gereksinimleri i\u00e7in geni\u015fletilebilir ve \u00f6zelle\u015ftirilebilir bir ba\u015flang\u0131\u00e7 noktas\u0131 sunar. \u00d6zellikle <code>JsonResponse<\/code> kullan\u0131m\u0131, frontend uygulamalar\u0131n\u0131n beklentilerini kar\u015f\u0131lamak i\u00e7in kritik \u00f6neme sahiptir.<\/p>\n<h2>Generic CBV'ler ile API'leri Nas\u0131l Geli\u015ftirebilirsiniz? ListView ve DetailView ile Veri Listeleme ve Detay G\u00f6r\u00fcnt\u00fcleme<\/h2>\n<p>\u00d6nceki b\u00f6l\u00fcmde <code>django.views.View<\/code> kullanarak s\u0131f\u0131rdan bir API olu\u015fturmay\u0131 g\u00f6rd\u00fck. Bu yakla\u015f\u0131m, tam kontrol sa\u011flasa da, belirli g\u00f6revler i\u00e7in tekrar eden kod yazmam\u0131za neden olabilir. Django, bu tekrarlardan ka\u00e7\u0131nmak ve daha h\u0131zl\u0131 geli\u015ftirme sa\u011flamak amac\u0131yla bir dizi \"Generic Class-Based Views\" sunar. Bu genel g\u00f6r\u00fcn\u00fcmler, belirli ortak web geli\u015ftirme senaryolar\u0131 i\u00e7in \u00f6nceden tan\u0131mlanm\u0131\u015f i\u015flevsellik sa\u011flarlar. \u00d6zellikle <code>ListView<\/code> ve <code>DetailView<\/code>, s\u0131ras\u0131yla bir koleksiyonu (\u00f6rne\u011fin, t\u00fcm \u00fcr\u00fcnler) ve tek bir \u00f6\u011feyi (\u00f6rne\u011fin, belirli bir \u00fcr\u00fcn\u00fcn detaylar\u0131) g\u00f6stermek i\u00e7in tasarlanm\u0131\u015ft\u0131r. Bu b\u00f6l\u00fcmde, bu generic CBV'leri API ba\u011flam\u0131nda nas\u0131l kullanabilece\u011fimizi inceleyece\u011fiz.<\/p>\n<p>Generic CBV'ler, varsay\u0131lan olarak bir HTML \u015fablonunu render etmek \u00fczere tasarlanm\u0131\u015ft\u0131r. Ancak, bizim API'lerimizde HTML de\u011fil, JSON format\u0131nda veri d\u00f6nd\u00fcrmemiz gerekiyor. Bu sorunu \u00e7\u00f6zmek i\u00e7in, bu generic g\u00f6r\u00fcn\u00fcmlerin davran\u0131\u015flar\u0131n\u0131 de\u011fi\u015ftirmemiz veya onlarla birlikte \u00e7al\u0131\u015facak \u00f6zel \"mixin\"ler (kar\u0131\u015f\u0131m s\u0131n\u0131flar\u0131) geli\u015ftirmemiz gerekecektir. Bir mixin, di\u011fer s\u0131n\u0131flara belirli bir davran\u0131\u015f veya i\u015flevsellik eklemek i\u00e7in tasarlanm\u0131\u015f bir s\u0131n\u0131ft\u0131r. Python'\u0131n \u00e7oklu kal\u0131t\u0131m yetene\u011fi sayesinde, bir mixin'i generic bir CBV ile birle\u015ftirerek istedi\u011fimiz JSON yan\u0131t\u0131 davran\u0131\u015f\u0131n\u0131 kolayca ekleyebiliriz.<\/p>\n<p>\u00d6ncelikle, basit bir <code>JsonMixin<\/code> olu\u015ftural\u0131m. Bu mixin, bir Python objesini JSON'a d\u00f6n\u00fc\u015ft\u00fcr\u00fcp <code>JsonResponse<\/code> ile yan\u0131t d\u00f6necek bir metot i\u00e7erecek. Ard\u0131ndan, <code>ListView<\/code> ve <code>DetailView<\/code> ile bu mixin'i birle\u015ftirerek API g\u00f6r\u00fcn\u00fcmlerimizi yeniden yap\u0131land\u0131raca\u011f\u0131z.<\/p>\n<h4>1. <code>JsonMixin<\/code> Olu\u015fturma<\/h4>\n<p><code>products_api\/mixins.py<\/code> ad\u0131nda yeni bir dosya olu\u015ftural\u0131m:<\/p>\n<pre><code class=\"language-python\">\n# products_api\/mixins.py\nimport json\nfrom django.http import JsonResponse\nfrom django.core.serializers import serialize\nfrom django.forms.models import model_to_dict\n\nclass JsonResponseMixin:\n    \"\"\"\n    Kal\u0131t\u0131ld\u0131\u011f\u0131 s\u0131n\u0131flar\u0131n get_context_data veya get_object gibi\n    metotlar\u0131ndan d\u00f6nen veriyi JSON format\u0131na \u00e7evirerek yan\u0131t verir.\n    \"\"\"\n    def render_to_json_response(self, context, **response_kwargs):\n        \"\"\"\n        Verilen i\u00e7eri\u011fi JSON format\u0131nda bir Http D\u00fczeyinde Yan\u0131t'a d\u00f6n\u00fc\u015ft\u00fcr\u00fcr.\n        \"\"\"\n        return JsonResponse(self.get_data_from_context(context), **response_kwargs)\n\n    def get_data_from_context(self, context):\n        \"\"\"\n        Ba\u011flamdan (context) JSON'a d\u00f6n\u00fc\u015ft\u00fcr\u00fclecek veriyi \u00e7\u0131kar\u0131r.\n        \"\"\"\n        # ListView i\u00e7in: object_list veya queryset\n        if 'object_list' in context:\n            # Django'nun kendi serializer'\u0131n\u0131 kullanmak daha esneklik sunar\n            # veya manuel olarak model_to_dict ile.\n            data = json.loads(serialize('json', context['object_list']))\n            # Sadece model verilerini al, Django'nun ekledi\u011fi 'model', 'pk' gibi alanlar\u0131 filtrele\n            return [d['fields'] for d in data]\n        # DetailView i\u00e7in: object\n        elif 'object' in context:\n            return model_to_dict(context['object'])\n        else:\n            # Di\u011fer durumlar veya \u00f6zel context verileri\n            return context\n\nclass JsonDeleteMixin:\n    \"\"\"\n    Silme i\u015flemleri i\u00e7in JSON yan\u0131t\u0131 d\u00f6nd\u00fcren mixin.\n    \"\"\"\n    def delete(self, request, *args, **kwargs):\n        self.object = self.get_object()\n        self.object.delete()\n        return JsonResponse({'message': 'Kaynak ba\u015far\u0131yla silindi.'}, status=204) # 204 No Content\n<\/pre>\n<p><\/code><\/p>\n<p>Buradaki <code>JsonResponseMixin<\/code>, <code>get_data_from_context<\/code> metodu ile <code>ListView<\/code>'in <code>object_list<\/code>'inden veya <code>DetailView<\/code>'in <code>object<\/code>'inden veriyi \u00e7ekip JSON'a d\u00f6n\u00fc\u015ft\u00fcr\u00fcyor. Django'nun <code>serialize<\/code> fonksiyonunu kullanarak modelleri JSON format\u0131na d\u00f6n\u00fc\u015ft\u00fcr\u00fcyoruz, bu, <code>model_to_dict<\/code>'e g\u00f6re daha geli\u015fmi\u015f serile\u015ftirme se\u00e7enekleri sunar.<\/p>\n<h4>2. Generic CBV'ler ile API G\u00f6r\u00fcn\u00fcmlerini G\u00fcncelleme<\/h4>\n<p>\u015eimdi <code>products_api\/views.py<\/code> dosyam\u0131z\u0131 g\u00fcncelleyelim. <code>ProductListView<\/code> ve <code>ProductDetailView<\/code> s\u0131n\u0131flar\u0131n\u0131 <code>JsonResponseMixin<\/code> ile birle\u015ftirerek yeniden yazaca\u011f\u0131z.<\/p>\n<pre><code class=\"language-python\">\n# products_api\/views.py (G\u00fcncellenmi\u015f)\nimport json\nfrom django.views.generic import ListView, DetailView\nfrom django.http import JsonResponse\nfrom django.forms.models import model_to_dict # Gerekliyse kullan\u0131labilir\nfrom django.core.exceptions import ValidationError\n\nfrom .models import Product\nfrom .mixins import JsonResponseMixin, JsonDeleteMixin # Yeni mixin'imizi dahil ediyoruz\n\nclass ProductListAPIView(JsonResponseMixin, ListView):\n    model = Product\n    context_object_name = 'products' # Varsay\u0131lan 'object_list' yerine 'products' kullanabiliriz\n\n    def get(self, request, *args, **kwargs):\n        # ListView'\u0131n get metodunu \u00e7a\u011f\u0131rarak object_list'i olu\u015fturur\n        response = super().get(request, *args, **kwargs)\n        # context'i al\u0131p JSON yan\u0131t\u0131na d\u00f6n\u00fc\u015ft\u00fcr\u00fcyoruz\n        return self.render_to_json_response(self.get_context_data())\n\n    def post(self, request, *args, **kwargs):\n        \"\"\"\n        Yeni bir \u00fcr\u00fcn olu\u015fturur.\n        \"\"\"\n        try:\n            data = json.loads(request.body.decode('utf-8'))\n            name = data.get('name')\n            description = data.get('description')\n            price = data.get('price')\n\n            if not all([name, description, price]):\n                return JsonResponse({'error': 'Ad, a\u00e7\u0131klama ve fiyat alanlar\u0131 zorunludur.'}, status=400)\n\n            # Do\u011frudan model.objects.create ile \u00fcr\u00fcn olu\u015fturma\n            product = Product.objects.create(name=name, description=description, price=price)\n            return JsonResponse(model_to_dict(product, fields=['id', 'name', 'description', 'price']), status=201)\n        except json.JSONDecodeError:\n            return JsonResponse({'error': 'Ge\u00e7ersiz JSON format\u0131.'}, status=400)\n        except ValidationError as e:\n            return JsonResponse({'error': e.message_dict}, status=400)\n        except Exception as e:\n            return JsonResponse({'error': str(e)}, status=500)\n\n\nclass ProductDetailAPIView(JsonResponseMixin, JsonDeleteMixin, DetailView):\n    model = Product\n    context_object_name = 'product' # Varsay\u0131lan 'object' yerine 'product' kullanabiliriz\n    pk_url_kwarg = 'pk' # URL'den gelen primary key arg\u00fcman\u0131n\u0131n ad\u0131\n\n    def get(self, request, *args, **kwargs):\n        # DetailView'\u0131n get metodunu \u00e7a\u011f\u0131rarak object'i olu\u015fturur\n        response = super().get(request, *args, **kwargs)\n        # context'i al\u0131p JSON yan\u0131t\u0131na d\u00f6n\u00fc\u015ft\u00fcr\u00fcyoruz\n        return self.render_to_json_response(self.get_context_data())\n\n    def put(self, request, *args, **kwargs):\n        \"\"\"\n        Belirli bir \u00fcr\u00fcn\u00fc g\u00fcnceller.\n        \"\"\"\n        self.object = self.get_object() # DetailView'\u0131n get_object metodunu kullanarak \u00fcr\u00fcn\u00fc al\u0131r\n        try:\n            data = json.loads(request.body.decode('utf-8'))\n\n            self.object.name = data.get('name', self.object.name)\n            self.object.description = data.get('description', self.object.description)\n            self.object.price = data.get('price', self.object.price)\n            self.object.full_clean() # Model do\u011frulamay\u0131 \u00e7al\u0131\u015ft\u0131r\u0131r\n            self.object.save()\n\n            return JsonResponse(model_to_dict(self.object, fields=['id', 'name', 'description', 'price']))\n        except json.JSONDecodeError:\n            return JsonResponse({'error': 'Ge\u00e7ersiz JSON format\u0131.'}, status=400)\n        except ValidationError as e:\n            return JsonResponse({'error': e.message_dict}, status=400)\n        except Exception as e:\n            return JsonResponse({'error': str(e)}, status=500)\n\n    # DELETE metodu art\u0131k JsonDeleteMixin taraf\u0131ndan sa\u011flan\u0131yor\n    # def delete(self, request, *args, **kwargs):\n    #     self.object = self.get_object()\n    #     self.object.delete()\n    #     return JsonResponse({'message': '\u00dcr\u00fcn ba\u015far\u0131yla silindi.'}, status=204)\n<\/pre>\n<p><\/code><\/p>\n<p>URL yap\u0131land\u0131rmas\u0131nda de\u011fi\u015fiklik yapmam\u0131za gerek yok, \u00e7\u00fcnk\u00fc sadece g\u00f6r\u00fcn\u00fcm s\u0131n\u0131flar\u0131n\u0131n i\u00e7 implementasyonunu de\u011fi\u015ftirdik, isimlerini de\u011fil. Art\u0131k <code>ProductListAPIView<\/code> ve <code>ProductDetailAPIView<\/code>, generic CBV'lerin sa\u011flad\u0131\u011f\u0131 kolayl\u0131klar\u0131 JSON yan\u0131tlar\u0131yla birle\u015ftirerek daha derli toplu bir API sunuyor. <code>get_context_data()<\/code> metodu, <code>ListView<\/code> ve <code>DetailView<\/code> taraf\u0131ndan otomatik olarak \u00e7a\u011fr\u0131lan ve \u015fablonlara g\u00f6nderilecek veriyi haz\u0131rlayan bir metottur. Biz bu veriyi al\u0131p JSON'a d\u00f6n\u00fc\u015ft\u00fcrerek HTTP yan\u0131t\u0131 olarak geri g\u00f6nderiyoruz.<\/p>\n<p>Bu yakla\u015f\u0131m, kod tekrar\u0131n\u0131 \u00f6nemli \u00f6l\u00e7\u00fcde azalt\u0131rken, Django'nun sa\u011flam ve test edilmi\u015f generic CBV yap\u0131s\u0131ndan faydalanmam\u0131z\u0131 sa\u011flar. \u00d6zellikle birden fazla model ve \u00e7e\u015fitli CRUD (Create, Read, Update, Delete) operasyonlar\u0131 i\u00e7eren karma\u015f\u0131k API'ler geli\u015ftirirken mixin'ler ve generic CBV'lerin birle\u015fimi b\u00fcy\u00fck bir avantaj sunar. Bu \u015fekilde, projeniz b\u00fcy\u00fcd\u00fck\u00e7e API kodunuz daha d\u00fczenli ve s\u00fcrd\u00fcr\u00fclebilir kal\u0131r.<\/p>\n<h2>Vaka Analizi: E-Ticaret Sepeti API'si<\/h2>\n<p>\u015eimdi \u00f6\u011frendiklerimizi ger\u00e7ek\u00e7i bir senaryoda uygulayal\u0131m: Basit bir E-ticaret Sepeti API'si olu\u015fturmak. Bu API, frontend uygulamalar\u0131n\u0131n kullan\u0131c\u0131lar\u0131n al\u0131\u015fveri\u015f sepetlerini y\u00f6netmesini sa\u011flayacak. Bir sepete \u00fcr\u00fcn ekleme, \u00fcr\u00fcn\u00fc g\u00fcncelleme ve sepetten \u00e7\u0131karma gibi temel i\u015flemleri kapsayacak.<\/p>\n<h4>1. Model Tan\u0131mlamalar\u0131<\/h4>\n<p>Al\u0131\u015fveri\u015f sepeti i\u00e7in iki model tan\u0131mlamam\u0131z gerekecek: <code>Cart<\/code> (sepetin kendisi) ve <code>CartItem<\/code> (sepetteki her bir \u00fcr\u00fcn). <code>Product<\/code> modelini daha \u00f6nceki b\u00f6l\u00fcmden kullanaca\u011f\u0131z.<\/p>\n<pre><code class=\"language-python\">\n# products_api\/models.py (G\u00fcncellenmi\u015f - Mevcut Product modelinin alt\u0131na ekleyin)\nfrom django.db import models\nfrom django.conf import settings # Kullan\u0131c\u0131 modeline eri\u015fmek i\u00e7in\n\n# Daha \u00f6nce tan\u0131mlanan Product modeli burada tekrar kullan\u0131lacak\n\nclass Cart(models.Model):\n    user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True)\n    created_at = models.DateTimeField(auto_now_add=True)\n    updated_at = models.DateTimeField(auto_now=True)\n\n    def __str__(self):\n        return f\"Sepet ({self.user.username if self.user else 'Anonim'})\"\n\nclass CartItem(models.Model):\n    cart = models.ForeignKey(Cart, related_name='items', on_delete=models.CASCADE)\n    product = models.ForeignKey(Product, on_delete=models.CASCADE)\n    quantity = models.PositiveIntegerField(default=1)\n    added_at = models.DateTimeField(auto_now_add=True)\n\n    def total_price(self):\n        return self.quantity * self.product.price\n\n    def __str__(self):\n        return f\"{self.quantity} x {self.product.name} ({self.cart.user.username if self.cart.user else 'Anonim Sepet'})\"\n\n    class Meta:\n        unique_together = ('cart', 'product') # Bir sepette ayn\u0131 \u00fcr\u00fcnden sadece bir tane olabilir\n<\/pre>\n<p><\/code><\/p>\n<p>Bu modelleri tan\u0131mlad\u0131ktan sonra tekrar veritaban\u0131 ge\u00e7i\u015flerini \u00e7al\u0131\u015ft\u0131r\u0131n:<\/p>\n<pre><code class=\"language-bash\">\npython manage.py makemigrations products_api\npython manage.py migrate\n<\/pre>\n<p><\/code><\/p>\n<h4>2. Sepet API G\u00f6r\u00fcn\u00fcm\u00fc Olu\u015fturma<\/h4>\n<p>Bu vaka analizinde, sepetle ilgili t\u00fcm i\u015flemleri (liste, ekleme, g\u00fcncelleme, silme) tek bir CBV alt\u0131nda toplayarak daha RESTful bir yakla\u015f\u0131m sergileyece\u011fiz. Kullan\u0131c\u0131n\u0131n sepetine eri\u015fmek i\u00e7in kimlik do\u011frulama gerekecek (basit bir \u00f6rnek i\u00e7in \u015fimdilik atl\u0131yoruz, ama ger\u00e7ek bir projede bu \u00f6nemlidir).<\/p>\n<pre><code class=\"language-python\">\n# products_api\/views.py (Sepet API'si i\u00e7in yeni bir g\u00f6r\u00fcn\u00fcm)\n# Mevcut import'lara ekleyin\nimport json\nfrom django.views import View\nfrom django.http import JsonResponse\nfrom django.forms.models import model_to_dict\nfrom django.db import transaction\nfrom django.core.exceptions import ObjectDoesNotExist, ValidationError\n\nfrom .models import Product, Cart, CartItem\n# Gerekliyse JsonResponseMixin kullan\u0131labilir, ama burada manuel serile\u015ftirme yap\u0131yoruz.\n\nclass CartAPIView(View):\n    def get_cart(self, request):\n        # Kullan\u0131c\u0131n\u0131n sepetini al veya olu\u015ftur.\n        # Ger\u00e7ek bir projede, burada kullan\u0131c\u0131 kimlik do\u011frulamas\u0131 kontrol edilmeli.\n        # Basitlik ad\u0131na, \u015fu an ilk kay\u0131tl\u0131 kullan\u0131c\u0131ya ba\u011fl\u0131 bir sepet veya yeni bir anonim sepet olu\u015fturulur.\n        user = request.user if request.user.is_authenticated else None\n        if user:\n            cart, created = Cart.objects.get_or_create(user=user)\n        else:\n            # Anonim sepetler i\u00e7in oturum tabanl\u0131 bir mekanizma gerekebilir.\n            # \u015eimdilik, her istekte yeni bir anonim sepet olu\u015fturuldu\u011funu varsayal\u0131m.\n            # Ger\u00e7ekte, session ID ile anonim sepetler ili\u015fkilendirilir.\n            cart = Cart.objects.create() # Her seferinde yeni anonim sepet, pratik de\u011fil ama \u00f6rnek i\u00e7in yeterli.\n        return cart\n\n    def serialize_cart_item(self, cart_item):\n        \"\"\"Tek bir sepet \u00f6\u011fesini s\u00f6zl\u00fc\u011fe d\u00f6n\u00fc\u015ft\u00fcr\u00fcr.\"\"\"\n        return {\n            'id': cart_item.id,\n            'product_id': cart_item.product.id,\n            'product_name': cart_item.product.name,\n            'quantity': cart_item.quantity,\n            'price_per_item': str(cart_item.product.price), # Decimal'\u0131 string'e \u00e7evir\n            'total_item_price': str(cart_item.total_price()),\n        }\n\n    def serialize_cart(self, cart):\n        \"\"\"Bir sepet objesini ve \u00f6\u011felerini s\u00f6zl\u00fc\u011fe d\u00f6n\u00fc\u015ft\u00fcr\u00fcr.\"\"\"\n        items_data = [self.serialize_cart_item(item) for item in cart.items.all()]\n        total_cart_price = sum(item.total_price() for item in cart.items.all())\n        return {\n            'id': cart.id,\n            'user': cart.user.username if cart.user else 'Anonim',\n            'created_at': cart.created_at.isoformat(),\n            'updated_at': cart.updated_at.isoformat(),\n            'items': items_data,\n            'total_cart_price': str(total_cart_price),\n        }\n\n    def get(self, request, *args, **kwargs):\n        \"\"\"\n        Kullan\u0131c\u0131n\u0131n sepet i\u00e7eri\u011fini listeler.\n        \"\"\"\n        cart = self.get_cart(request)\n        return JsonResponse(self.serialize_cart(cart))\n\n    def post(self, request, *args, **kwargs):\n        \"\"\"\n        Sepete \u00fcr\u00fcn ekler veya mevcut \u00fcr\u00fcn\u00fcn miktar\u0131n\u0131 g\u00fcnceller.\n        \"\"\"\n        cart = self.get_cart(request)\n        try:\n            data = json.loads(request.body.decode('utf-8'))\n            product_id = data.get('product_id')\n            quantity = data.get('quantity', 1)\n\n            if not product_id:\n                return JsonResponse({'error': 'product_id zorunludur.'}, status=400)\n            if not isinstance(quantity, int) or quantity <= 0:\n                return JsonResponse({'error': 'quantity pozitif bir tam say\u0131 olmal\u0131d\u0131r.'}, status=400)\n\n            product = Product.objects.get(pk=product_id)\n\n            with transaction.atomic(): # Atomik i\u015flem, hata durumunda geri alma\n                cart_item, created = CartItem.objects.get_or_create(\n                    cart=cart,\n                    product=product,\n                    defaults={'quantity': quantity}\n                )\n                if not created:\n                    cart_item.quantity += quantity # E\u011fer \u00fcr\u00fcn sepette varsa miktar\u0131n\u0131 art\u0131r\n                    cart_item.save()\n\n                cart.save() # Sepetin updated_at alan\u0131n\u0131 g\u00fcncelle\n\n            return JsonResponse(self.serialize_cart_item(cart_item), status=201 if created else 200)\n\n        except json.JSONDecodeError:\n            return JsonResponse({'error': 'Ge\u00e7ersiz JSON format\u0131.'}, status=400)\n        except Product.DoesNotExist:\n            return JsonResponse({'error': '\u00dcr\u00fcn bulunamad\u0131.'}, status=404)\n        except Exception as e:\n            return JsonResponse({'error': str(e)}, status=500)\n\n    def put(self, request, pk=None, *args, **kwargs):\n        \"\"\"\n        Sepetteki belirli bir \u00fcr\u00fcn\u00fcn miktar\u0131n\u0131 g\u00fcnceller (pk, CartItem ID'si).\n        \"\"\"\n        if not pk:\n            return JsonResponse({'error': 'G\u00fcncellenecek sepet \u00f6\u011fesinin ID\\'si (pk) zorunludur.'}, status=400)\n        \n        cart = self.get_cart(request)\n        try:\n            data = json.loads(request.body.decode('utf-8'))\n            new_quantity = data.get('quantity')\n\n            if not isinstance(new_quantity, int) or new_quantity <= 0:\n                return JsonResponse({'error': 'quantity pozitif bir tam say\u0131 olmal\u0131d\u0131r.'}, status=400)\n\n            cart_item = cart.items.get(pk=pk) # Sadece kullan\u0131c\u0131n\u0131n sepetindeki \u00f6\u011feleri g\u00fcncellesin\n            cart_item.quantity = new_quantity\n            cart_item.full_clean()\n            cart_item.save()\n            cart.save() # Sepetin updated_at alan\u0131n\u0131 g\u00fcncelle\n\n            return JsonResponse(self.serialize_cart_item(cart_item))\n\n        except json.JSONDecodeError:\n            return JsonResponse({'error': 'Ge\u00e7ersiz JSON format\u0131.'}, status=400)\n        except CartItem.DoesNotExist:\n            return JsonResponse({'error': 'Sepette b\u00f6yle bir \u00f6\u011fe bulunamad\u0131.'}, status=404)\n        except ValidationError as e:\n            return JsonResponse({'error': e.message_dict}, status=400)\n        except Exception as e:\n            return JsonResponse({'error': str(e)}, status=500)\n\n    def delete(self, request, pk=None, *args, **kwargs):\n        \"\"\"\n        Sepetten belirli bir \u00fcr\u00fcn\u00fc \u00e7\u0131kar\u0131r (pk, CartItem ID'si).\n        \"\"\"\n        if not pk:\n            return JsonResponse({'error': 'Silinecek sepet \u00f6\u011fesinin ID\\'si (pk) zorunludur.'}, status=400)\n        \n        cart = self.get_cart(request)\n        try:\n            cart_item = cart.items.get(pk=pk) # Sadece kullan\u0131c\u0131n\u0131n sepetindeki \u00f6\u011feleri silsin\n            cart_item.delete()\n            cart.save() # Sepetin updated_at alan\u0131n\u0131 g\u00fcncelle\n            return JsonResponse({'message': '\u00dcr\u00fcn sepetten ba\u015far\u0131yla silindi.'}, status=204) # 204 No Content\n        except CartItem.DoesNotExist:\n            return JsonResponse({'error': 'Sepette b\u00f6yle bir \u00f6\u011fe bulunamad\u0131.'}, status=404)\n        except Exception as e:\n            return JsonResponse({'error': str(e)}, status=500)\n<\/pre>\n<p><\/code><\/p>\n<div class=\"expert-tip\">\n    Uzman \u0130pucu: Ger\u00e7ek bir e-ticaret uygulamas\u0131nda, anonim sepetler genellikle taray\u0131c\u0131 \u00e7erezleri veya oturum ID'leri arac\u0131l\u0131\u011f\u0131yla y\u00f6netilir. Kullan\u0131c\u0131 giri\u015f yapt\u0131\u011f\u0131nda anonim sepet, kullan\u0131c\u0131n\u0131n mevcut sepetiyle birle\u015ftirilir. Bu \u00f6rnek, konuyu basitle\u015ftirmek ad\u0131na daha do\u011frudan bir yakla\u015f\u0131md\u0131r.\n<\/div>\n<h4>3. URL Yap\u0131land\u0131rmas\u0131<\/h4>\n<p>Sepet API'mizi URL'lere ba\u011flayal\u0131m. Burada bir sepet \u00f6\u011fesinin ID'si (<code>pk<\/code>) ile i\u015flem yapaca\u011f\u0131m\u0131z i\u00e7in dinamik URL'lere ihtiyac\u0131m\u0131z var.<\/p>\n<pre><code class=\"language-python\">\n# products_api\/urls.py (G\u00fcncellenmi\u015f - mevcut urlpatterns listesine ekleyin)\nfrom django.urls import path\nfrom .views import ProductListAPIView, ProductDetailAPIView, CartAPIView\n\nurlpatterns = [\n    # ... mevcut \u00fcr\u00fcn API URL'leri\n    path('products\/', ProductListAPIView.as_view(), name='product-list-api'),\n    path('products\/<int:pk>\/', ProductDetailAPIView.as_view(), name='product-detail-api'),\n\n    # Sepet API URL'leri\n    path('cart\/', CartAPIView.as_view(), name='cart-list-create'),\n    path('cart\/<int:pk>\/', CartAPIView.as_view(), name='cart-item-detail-update-delete'),\n]\n<\/pre>\n<p><\/code><\/p>\n<p>Bu <code>CartAPIView<\/code> \u00f6rne\u011fi, tek bir CBV'nin hem liste\/olu\u015fturma hem de detay\/g\u00fcncelleme\/silme i\u015flemlerini nas\u0131l y\u00f6netebilece\u011fini g\u00f6stermektedir. <code>get_cart<\/code> metodu, request'ten kullan\u0131c\u0131y\u0131 alarak ona ait sepeti bulur veya yeni bir sepet olu\u015fturur. Serile\u015ftirme i\u015flemleri, <code>serialize_cart_item<\/code> ve <code>serialize_cart<\/code> \u00f6zel metotlar\u0131 ile yap\u0131lm\u0131\u015ft\u0131r. Bu, verinin tam olarak nas\u0131l yap\u0131land\u0131r\u0131laca\u011f\u0131 \u00fczerinde bize tam kontrol sa\u011flar ve Django REST Framework'\u00fcn serializer'lar\u0131na benzer bir i\u015flevsellik sunar.<\/p>\n<p>Bu vaka analizi, CBV'lerin karma\u015f\u0131k i\u015f mant\u0131klar\u0131n\u0131 ve \u00e7oklu HTTP metotlar\u0131n\u0131 tek bir s\u0131n\u0131f i\u00e7inde nas\u0131l zarif bir \u015fekilde y\u00f6netebilece\u011fini g\u00f6zler \u00f6n\u00fcne seriyor. \u00d6zellikle <code>transaction.atomic()<\/code> kullan\u0131m\u0131, sepet i\u015flemlerinde veri tutarl\u0131l\u0131\u011f\u0131n\u0131 sa\u011flamak i\u00e7in kritik \u00f6neme sahiptir. Bu yap\u0131, frontend uygulamalar\u0131n\u0131n bir kullan\u0131c\u0131n\u0131n sepetiyle etkile\u015fime girmesi i\u00e7in g\u00fc\u00e7l\u00fc ve esnek bir API taban\u0131 sunar.<\/p>\n<h2>Geli\u015fmi\u015f Konular ve Optimizasyon \u0130pu\u00e7lar\u0131: Performans, G\u00fcvenlik ve Mobil Uyumlu API Tasar\u0131m\u0131<\/h2>\n<p>Bir API olu\u015fturmak sadece veri al\u0131\u015fveri\u015fini sa\u011flamakla kalmaz, ayn\u0131 zamanda performans, g\u00fcvenlik ve kullan\u0131labilirlik gibi kritik fakt\u00f6rleri de g\u00f6z \u00f6n\u00fcnde bulundurmay\u0131 gerektirir. \u00d6zellikle frontend uygulamalar\u0131, h\u0131zl\u0131 yan\u0131t veren ve g\u00fcvenilir API'lere ihtiya\u00e7 duyar. Bu b\u00f6l\u00fcmde, Django CBV tabanl\u0131 API'lerinizi daha robust hale getirecek ileri d\u00fczey konulara ve optimizasyon ipu\u00e7lar\u0131na de\u011finece\u011fiz.<\/p>\n<h3>Performans Optimizasyonu: API'nizi H\u0131zland\u0131r\u0131n<\/h3>\n<p>Yava\u015f API'ler, kullan\u0131c\u0131 deneyimini do\u011frudan etkileyen \u00f6nemli bir fakt\u00f6rd\u00fcr. Veritaban\u0131 sorgular\u0131 genellikle performans darbo\u011fazlar\u0131n\u0131n ana kayna\u011f\u0131d\u0131r. Django ORM'i, bu sorgular\u0131 optimize etmek i\u00e7in g\u00fc\u00e7l\u00fc ara\u00e7lar sunar:<\/p>\n<ul>\n<li><strong><code>select_related()<\/code> ve <code>prefetch_related()<\/code>:<\/strong> N+1 sorgu sorununu \u00e7\u00f6zmek i\u00e7in bu metotlar\u0131 kullan\u0131n. <code>select_related()<\/code>, tekil ili\u015fkileri (ForeignKey, OneToOneField) tek bir JOIN sorgusu ile getirirken, <code>prefetch_related()<\/code>, \u00e7oklu ili\u015fkileri (ManyToOne, ManyToMany) ayr\u0131 bir sorguda getirip Python taraf\u0131nda birle\u015ftirir. Bu, \u00f6zellikle bir nesnenin ili\u015fkili oldu\u011fu di\u011fer nesneleri de s\u0131k\u00e7a g\u00f6stermeniz gerekti\u011finde \u00e7ok \u00f6nemlidir.<\/li>\n<li><strong>Pagination (Sayfaland\u0131rma):<\/strong> B\u00fcy\u00fck veri setlerini tek bir yan\u0131tta d\u00f6nd\u00fcrmek yerine, veriyi sayfalara ay\u0131r\u0131n. Bu, hem sunucu y\u00fck\u00fcn\u00fc azalt\u0131r hem de frontend'in daha az veriyle ba\u015fa \u00e7\u0131kmas\u0131n\u0131 sa\u011flar. Django'nun kendi <code>Paginator<\/code> s\u0131n\u0131f\u0131n\u0131 veya custom bir mixin'i kullanarak sayfaland\u0131rma mant\u0131\u011f\u0131 ekleyebilirsiniz.<\/li>\n<li><strong>Caching (\u00d6nbellekleme):<\/strong> S\u0131k\u00e7a istenen ancak nadiren de\u011fi\u015fen veriler i\u00e7in \u00f6nbellekleme kullan\u0131n. Django'nun \u00f6nbellekleme \u00e7er\u00e7evesi veya Redis\/Memcached gibi harici \u00e7\u00f6z\u00fcmlerle API yan\u0131tlar\u0131n\u0131 veya veritaban\u0131 sorgular\u0131n\u0131 \u00f6nbelle\u011fe alabilirsiniz. Bu, veritaban\u0131 y\u00fck\u00fcn\u00fc ve yan\u0131t s\u00fcrelerini \u00f6nemli \u00f6l\u00e7\u00fcde azalt\u0131r.<\/li>\n<\/ul>\n<pre><code class=\"language-python\">\n# products_api\/views.py - select_related \u00f6rne\u011fi\nfrom django.views.generic import ListView\nfrom .models import CartItem\n\nclass OptimizedCartItemListView(ListView):\n    model = CartItem\n    # product ile ili\u015fkili verileri tek sorguda getirir\n    queryset = CartItem.objects.select_related('product', 'cart').all() \n    # ... di\u011fer metotlar ve serile\u015ftirme mant\u0131\u011f\u0131\n<\/pre>\n<p><\/code><\/p>\n<div class=\"expert-tip\">\n    Uzman \u0130pucu: \u00d6nbellekleme stratejileri uygularken \"cache invalidation\" (\u00f6nbellek ge\u00e7ersizle\u015ftirme) konusunu dikkatlice planlay\u0131n. Veri de\u011fi\u015fti\u011finde ilgili \u00f6nbelle\u011fi do\u011fru zamanda temizlemek, eski verilerin sunulmas\u0131n\u0131 engeller.\n<\/div>\n<h3>G\u00fcvenlik: API'nizi Koruma Alt\u0131na Al\u0131n<\/h3>\n<p>API'ler, uygulaman\u0131z\u0131n hassas verilerine eri\u015fim sa\u011flad\u0131\u011f\u0131 i\u00e7in g\u00fcvenlik b\u00fcy\u00fck \u00f6nem ta\u015f\u0131r:<\/p>\n<ul>\n<li><strong>Kimlik Do\u011frulama (Authentication):<\/strong> API'ye eri\u015fen kullan\u0131c\u0131n\u0131n kimli\u011fini do\u011frulay\u0131n. Django'nun varsay\u0131lan oturum tabanl\u0131 kimlik do\u011frulamas\u0131n\u0131n yan\u0131 s\u0131ra, token tabanl\u0131 (\u00f6rne\u011fin JWT - JSON Web Tokens) veya OAuth2 gibi yakla\u015f\u0131mlar API'ler i\u00e7in daha uygun olabilir. <code>django-rest-framework-simplejwt<\/code> gibi paketler pop\u00fcler token tabanl\u0131 \u00e7\u00f6z\u00fcmler sunar. CBV'lerinizde <code>@method_decorator(login_required)<\/code> gibi dekorat\u00f6rler veya \u00f6zel mixin'ler kullanarak kimlik do\u011frulamas\u0131n\u0131 uygulayabilirsiniz.<\/li>\n<li><strong>Yetkilendirme (Authorization):<\/strong> Kimli\u011fi do\u011frulanm\u0131\u015f bir kullan\u0131c\u0131n\u0131n belirli bir kayna\u011fa eri\u015fim veya belirli bir i\u015flemi yapma izni olup olmad\u0131\u011f\u0131n\u0131 kontrol edin. Django'nun izin sistemini kullanabilir veya her view\/mixin i\u00e7inde kendi yetkilendirme mant\u0131\u011f\u0131n\u0131z\u0131 yazabilirsiniz.<\/li>\n<li><strong>HTTPS Kullan\u0131m\u0131:<\/strong> T\u00fcm API ileti\u015fimini HTTPS \u00fczerinden \u015fifreleyin. Bu, \u00f6zellikle hassas verilerin iletimi s\u0131ras\u0131nda verilerin k\u00f6t\u00fc niyetli ki\u015filerin eline ge\u00e7mesini engeller.<\/li>\n<li><strong>CSRF Korumas\u0131:<\/strong> Django, varsay\u0131lan olarak CSRF (Cross-Site Request Forgery) korumas\u0131 sa\u011flar. API'lerinizde, \u00f6zellikle oturum tabanl\u0131 kimlik do\u011frulama kullan\u0131yorsan\u0131z, POST, PUT, DELETE gibi g\u00fcvenli\u011fi etkileyebilecek istekler i\u00e7in CSRF token'\u0131 g\u00f6ndermeyi unutmay\u0131n. Token tabanl\u0131 kimlik do\u011frulama kullan\u0131yorsan\u0131z, CSRF genellikle gerekli de\u011fildir.<\/li>\n<li><strong>Giri\u015f Limitleri ve H\u0131z S\u0131n\u0131rlamas\u0131:<\/strong> Kaba kuvvet sald\u0131r\u0131lar\u0131n\u0131 veya hizmet reddi sald\u0131r\u0131lar\u0131n\u0131 \u00f6nlemek i\u00e7in API endpoint'lerine eri\u015fim h\u0131z\u0131n\u0131 s\u0131n\u0131rlay\u0131n.<\/li>\n<\/ul>\n<h3>Hata Y\u00f6netimi ve Durum Kodlar\u0131<\/h3>\n<p>API'ler, ba\u015far\u0131l\u0131 yan\u0131tlar kadar hatal\u0131 yan\u0131tlar\u0131 da anla\u015f\u0131l\u0131r bir \u015fekilde sunmal\u0131d\u0131r. Standart HTTP durum kodlar\u0131n\u0131 kullanmak (200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 500 Internal Server Error vb.), frontend uygulamalar\u0131n\u0131n hatalar\u0131 kolayca tan\u0131mas\u0131n\u0131 ve uygun \u015fekilde yan\u0131t vermesini sa\u011flar. Her hata mesaj\u0131, sorunu a\u00e7\u0131klayan bilgilendirici bir JSON objesi i\u00e7ermelidir.<\/p>\n<pre><code class=\"language-python\">\n# products_api\/views.py - Hata y\u00f6netimi \u00f6rne\u011fi\nfrom django.http import JsonResponse\nfrom django.core.exceptions import ObjectDoesNotExist, ValidationError\n\nclass MyAPIView(View):\n    def post(self, request):\n        try:\n            # \u0130\u015f mant\u0131\u011f\u0131\n            pass\n        except ObjectDoesNotExist:\n            return JsonResponse({'error': 'Kaynak bulunamad\u0131.'}, status=404)\n        except ValidationError as e:\n            return JsonResponse({'error': e.message_dict}, status=400) # Form veya model do\u011frulamas\u0131 hatalar\u0131\n        except Exception as e:\n            # Beklenmedik hatalar i\u00e7in genel bir 500 yan\u0131t\u0131\n            return JsonResponse({'error': 'Sunucu hatas\u0131 olu\u015ftu.', 'detail': str(e)}, status=500)\n<\/pre>\n<p><\/code><\/p>\n<h3>Mobil Uyumlu API Tasar\u0131m\u0131<\/h3>\n<p>Mobil uygulamalar genellikle k\u0131s\u0131tl\u0131 bant geni\u015fli\u011fine ve i\u015flem g\u00fcc\u00fcne sahip oldu\u011fu i\u00e7in API tasar\u0131m\u0131nda baz\u0131 \u00f6zel yakla\u015f\u0131mlar \u00f6nemlidir:<\/p>\n<ul>\n<li><strong>Hafif Yan\u0131tlar:<\/strong> Yaln\u0131zca frontend'in ger\u00e7ekten ihtiya\u00e7 duydu\u011fu veriyi d\u00f6nd\u00fcr\u00fcn. Gereksiz alanlar\u0131 filtrelemek veya farkl\u0131 cihazlar i\u00e7in farkl\u0131 serile\u015ftirme profilleri olu\u015fturmak faydal\u0131 olabilir.<\/li>\n<li><strong>S\u00fcr\u00fcmleme (Versioning):<\/strong> API'nizin evrimle\u015fece\u011fini unutmay\u0131n. URL (<code>\/api\/v1\/products\/<\/code>), ba\u015fl\u0131k (<code>Accept-version: v2<\/code>) veya sorgu parametresi (<code>?version=3<\/code>) ile API s\u00fcr\u00fcmlemesi yaparak eski istemcilerin \u00e7al\u0131\u015fmaya devam etmesini sa\u011flay\u0131n.<\/li>\n<li><strong>Performans:<\/strong> Yukar\u0131da bahsedilen performans optimizasyonlar\u0131 mobil uyumluluk i\u00e7in de kritiktir. Daha h\u0131zl\u0131 yan\u0131tlar, daha iyi mobil deneyim anlam\u0131na gelir.<\/li>\n<li><strong>Resim ve Medya Optimizasyonu:<\/strong> Mobil uygulamalar i\u00e7in optimize edilmi\u015f resim boyutlar\u0131 ve CDN (Content Delivery Network) kullan\u0131m\u0131, y\u00fckleme s\u00fcrelerini \u00f6nemli \u00f6l\u00e7\u00fcde azalt\u0131r. API, medya dosyalar\u0131n\u0131n URL'lerini d\u00f6nd\u00fcrmeli, dosyalar\u0131n kendisini de\u011fil.<\/li>\n<\/ul>\n<p>Bu geli\u015fmi\u015f konular, sadece i\u015flevsel de\u011fil, ayn\u0131 zamanda g\u00fcvenilir, h\u0131zl\u0131 ve \u00f6l\u00e7eklenebilir API'ler olu\u015fturman\u0131z i\u00e7in temel ta\u015flar\u0131d\u0131r. Django CBV'lerinin esnek yap\u0131s\u0131 sayesinde, bu optimizasyonlar\u0131 ve g\u00fcvenlik \u00f6nlemlerini projenizin ihtiya\u00e7lar\u0131na g\u00f6re entegre edebilirsiniz.<\/p>\n<h2>Django CBV'lerle API Geli\u015ftirmenin G\u00fcc\u00fc ve Esnekli\u011fi<\/h2>\n<p>Bu makale boyunca, Django Class-Based Views (CBV) kullanarak modern frontend uygulamalar\u0131 i\u00e7in nas\u0131l g\u00fc\u00e7l\u00fc ve esnek API'ler in\u015fa edilece\u011fini ad\u0131m ad\u0131m inceledik. Geleneksel Django \u015fablonlar\u0131ndan farkl\u0131 olarak, CBV'ler sayesinde JSON format\u0131nda veri d\u00f6nd\u00fcren, RESTful prensiplere uygun backend servisleri geli\u015ftirebildik. Temel <code>django.views.View<\/code> s\u0131n\u0131f\u0131ndan ba\u015flayarak, generic CBV'ler olan <code>ListView<\/code> ve <code>DetailView<\/code>'i nas\u0131l \u00f6zelle\u015ftirebilece\u011fimizi g\u00f6rd\u00fck. Ayr\u0131ca, mixin'lerin kod tekrar\u0131n\u0131 azaltma ve API mant\u0131\u011f\u0131n\u0131 mod\u00fclerle\u015ftirme konusundaki kritik rol\u00fcn\u00fc de ke\u015ffettik.<\/p>\n<p>Bir e-ticaret sepeti API'si \u00f6rne\u011fiyle, CBV'lerin karma\u015f\u0131k i\u015f mant\u0131klar\u0131n\u0131 ve CRUD operasyonlar\u0131n\u0131 tek bir s\u0131n\u0131f alt\u0131nda nas\u0131l y\u00f6netece\u011fini pratik bir senaryoyla deneyimledik. Bu, CBV'lerin sadece basit veri listelemekle kalmay\u0131p, ayn\u0131 zamanda dinamik ve etkile\u015fimli uygulamalar\u0131n belkemi\u011fini olu\u015fturan karma\u015f\u0131k i\u015flemleri de ba\u015far\u0131yla ele alabilece\u011fini g\u00f6stermektedir. Son olarak, performans optimizasyonlar\u0131 (sorgu iyile\u015ftirmeleri, \u00f6nbellekleme), g\u00fcvenlik \u00f6nlemleri (kimlik do\u011frulama, yetkilendirme) ve mobil uyumluluk gibi ileri d\u00fczey konulara de\u011findik. Bu konular, API'nizin sadece \"\u00e7al\u0131\u015fmas\u0131n\u0131\" de\u011fil, ayn\u0131 zamanda \"iyi \u00e7al\u0131\u015fmas\u0131n\u0131\" ve g\u00fcvenli olmas\u0131n\u0131 sa\u011flar, bu da modern web ve mobil uygulamalar i\u00e7in hayati \u00f6neme sahiptir.<\/p>\n<p>Django'nun kendi CBV yap\u0131s\u0131yla API geli\u015ftirmenin sundu\u011fu en b\u00fcy\u00fck avantajlardan biri, gerekti\u011finde tam kontrol sa\u011flamas\u0131 ve gereksiz ba\u011f\u0131ml\u0131l\u0131klardan ka\u00e7\u0131nma olana\u011f\u0131 sunmas\u0131d\u0131r. E\u011fer projenizin API gereksinimleri olduk\u00e7a spesifikse veya Django REST Framework'\u00fcn getirdi\u011fi ek \"magic\"ten ka\u00e7\u0131nmak istiyorsan\u0131z, CBV'ler m\u00fckemmel bir ba\u015flang\u0131\u00e7 noktas\u0131d\u0131r. Ancak, daha b\u00fcy\u00fck, daha karma\u015f\u0131k ve s\u00fcrekli geli\u015fen API'ler i\u00e7in DRF gibi \u00f6zel bir \u00e7er\u00e7evenin sundu\u011fu ek \u00f6zellikler (geli\u015fmi\u015f serile\u015ftiriciler, otomatik URL y\u00f6nlendirme, kapsaml\u0131 kimlik do\u011frulama sistemleri) geli\u015ftirme h\u0131z\u0131n\u0131z\u0131 \u00f6nemli \u00f6l\u00e7\u00fcde art\u0131rabilir. \u00d6nemli olan, projenizin mevcut ihtiya\u00e7lar\u0131n\u0131 ve gelecekteki \u00f6l\u00e7eklenebilirlik hedeflerini g\u00f6z \u00f6n\u00fcnde bulundurarak en uygun arac\u0131 se\u00e7mektir. Django CBV'ler, bu yolculukta size sa\u011flam ve esnek bir temel sunar.<\/p>\n<h3>S\u0131k\u00e7a Sorulan Sorular<\/h3>\n<h4>Soru 1: CBV'ler yerine Function-Based Views (FBV) ne zaman kullanmal\u0131y\u0131m?<\/h4>\n<p>Cevap 1: Basit, tek seferlik i\u015flemler veya \u00e7ok \u00f6zel mant\u0131k gerektiren durumlar i\u00e7in FBV'ler daha h\u0131zl\u0131 ve anla\u015f\u0131lmas\u0131 daha kolay olabilir. \u00d6zellikle k\u00fc\u00e7\u00fck bir API endpoint'i veya \u00f6zel bir veri i\u015fleme g\u00f6reviniz varsa ve bunu herhangi bir ba\u015fka g\u00f6r\u00fcn\u00fcmle payla\u015fma niyetiniz yoksa FBV'ler yeterli olabilir. Ancak, kod tekrar\u0131n\u0131 azaltmak, kal\u0131t\u0131m ve mod\u00fclerlikten faydalanmak ve \u00f6l\u00e7eklenebilirlik i\u00e7in genellikle CBV'ler tercih edilir.<\/p>\n<h4>Soru 2: Django REST Framework (DRF) yerine neden sadece CBV'leri kullanmal\u0131y\u0131m?<\/h4>\n<p>Cevap 2: DRF, karma\u015f\u0131k API'ler i\u00e7in harika bir se\u00e7imdir; ancak projenizin API gereksinimleri nispeten basitse, \u00e7ok fazla otomatik serile\u015ftirmeye veya geli\u015fmi\u015f kimlik do\u011frulama\/yetkilendirme \u00f6zelliklerine ihtiyac\u0131n\u0131z yoksa veya DRF'nin getirdi\u011fi ek ba\u011f\u0131ml\u0131l\u0131klardan ka\u00e7\u0131nmak istiyorsan\u0131z, standart CBV'ler yeterli olabilir. DRF, serile\u015ftirme, kimlik do\u011frulama, yetkilendirme gibi bir\u00e7ok \u00f6zelli\u011fi kutudan \u00e7\u0131kt\u0131\u011f\u0131 haliyle sunar, bu da h\u0131zl\u0131 geli\u015ftirme i\u00e7in idealdir. CBV'ler ile bu \u00f6zelliklerin baz\u0131lar\u0131n\u0131 kendiniz uygulaman\u0131z gerekebilir, bu da size daha fazla kontrol sa\u011flar.<\/p>\n<h4>Soru 3: API'mde veri do\u011frulamas\u0131n\u0131 nas\u0131l yapmal\u0131y\u0131m?<\/h4>\n<p>Cevap 3: Basit do\u011frulamalar i\u00e7in <code>request.POST<\/code> veya <code>request.body<\/code>'den gelen verileri do\u011frudan view i\u00e7inde if-else bloklar\u0131yla kontrol edebilirsiniz. Daha karma\u015f\u0131k senaryolar i\u00e7in Django'nun kendi <code>django.forms<\/code> mod\u00fcl\u00fcn\u00fc kullanarak form s\u0131n\u0131flar\u0131 olu\u015fturabilir ve bunlar\u0131 API verilerinizi do\u011frulamak i\u00e7in kullanabilirsiniz. Ayr\u0131ca, modellerinizin <code>clean()<\/code> metotlar\u0131n\u0131 veya <code>full_clean()<\/code> metodunu \u00e7a\u011f\u0131rarak model d\u00fczeyinde do\u011frulamadan faydalanabilirsiniz. Django REST Framework kullan\u0131yorsan\u0131z, serializer s\u0131n\u0131flar\u0131 geli\u015fmi\u015f ve merkezi bir do\u011frulama mekanizmas\u0131 sunar.<\/p>\n<h4>Soru 4: CBV tabanl\u0131 API'lerimin g\u00fcvenli\u011fini nas\u0131l sa\u011flayabilirim?<\/h4>\n<p>Cevap 4: Kimlik do\u011frulama i\u00e7in <code>django.contrib.auth<\/code> mod\u00fcl\u00fcn\u00fcn sa\u011flad\u0131\u011f\u0131 oturum tabanl\u0131 kimlik do\u011frulamay\u0131 veya \u00fc\u00e7\u00fcnc\u00fc taraf paketler (\u00f6rne\u011fin <code>django-rest-framework-simplejwt<\/code> gibi JWT tabanl\u0131 \u00e7\u00f6z\u00fcmler) kullan\u0131n. CBV'lerinizde <code>@method_decorator(login_required)<\/code> gibi dekorat\u00f6rler veya \u00f6zel bir mixin yazarak kimlik do\u011frulama kontrol\u00fc yapabilirsiniz. Yetkilendirme i\u00e7in Django'nun izin sistemini (<code>user.has_perm()<\/code>) veya \u00f6zel bir mixin yazarak uygulayabilirsiniz. Ayr\u0131ca, t\u00fcm API trafi\u011finizin HTTPS \u00fczerinden ger\u00e7ekle\u015fti\u011finden emin olun ve hassas bilgileri g\u00fcvenli bir \u015fekilde saklay\u0131n.<\/p>\n<h4>Soru 5: Mobil uyumluluk i\u00e7in API'mde nelere dikkat etmeliyim?<\/h4>\n<p>Cevap 5: Mobil uygulamalar genellikle k\u0131s\u0131tl\u0131 bant geni\u015fli\u011fi ve daha d\u00fc\u015f\u00fck i\u015flem g\u00fcc\u00fcne sahiptir. Bu nedenle API'nizin h\u0131zl\u0131 yan\u0131t vermesi, minimum veri g\u00f6ndermesi (gereksiz alanlardan ka\u00e7\u0131nma) ve s\u00fcr\u00fcmlemeyi desteklemesi \u00f6nemlidir. JSON format\u0131 genellikle hafiftir ve mobil uygulamalar i\u00e7in uygundur. Resimler gibi b\u00fcy\u00fck dosyalar i\u00e7in bir CDN (Content Delivery Network) kullanmak ve optimize edilmi\u015f medya boyutlar\u0131 sunmak performans\u0131 art\u0131r\u0131r. Ayr\u0131ca, API yan\u0131tlar\u0131n\u0131n k\u00fc\u00e7\u00fck ekranlarda kolayca i\u015flenebilecek \u015fekilde yap\u0131land\u0131r\u0131ld\u0131\u011f\u0131ndan ve mobil uygulaman\u0131n ihtiya\u00e7 duymad\u0131\u011f\u0131 b\u00fcy\u00fck veri bloklar\u0131n\u0131n g\u00f6nderilmedi\u011finden emin olun.<\/p>\n<p><\/body><\/p>\n","protected":false},"excerpt":{"rendered":"Bir Django projesinde Class-Based Views (CBV) kullanarak verimli ve \u00f6l\u00e7eklenebilir API&#8217;ler nas\u0131l olu\u015fturulur? Frontend ile sorunsuz entegrasyon i\u00e7in&hellip;","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_page_header_type":"","csco_page_load_nextpost":"","csco_page_subscribe_form":"","csco_page_contact_form":"","footnotes":""},"categories":[1],"tags":[],"class_list":{"0":"post-31772","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-genel","7":"cs-entry","8":"cs-video-wrap"},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.5 (Yoast SEO v25.3.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler<\/title>\n<meta name=\"description\" content=\"Bir Django projesinde Class-Based Views (CBV) kullanarak verimli ve \u00f6l\u00e7eklenebilir API&#039;ler nas\u0131l olu\u015fturulur? Frontend ile sorunsuz entegrasyon i\u00e7in ad\u0131m ad\u0131m rehberimizle ke\u015ffedin, modern web uygulamalar\u0131n\u0131z i\u00e7in g\u00fc\u00e7l\u00fc backend \u00e7\u00f6z\u00fcmleri geli\u015ftirin.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler\" \/>\n<meta property=\"og:description\" content=\"Bir Django projesinde Class-Based Views (CBV) kullanarak verimli ve \u00f6l\u00e7eklenebilir API&#039;ler nas\u0131l olu\u015fturulur? Frontend ile sorunsuz entegrasyon i\u00e7in ad\u0131m ad\u0131m rehberimizle ke\u015ffedin, modern web uygulamalar\u0131n\u0131z i\u00e7in g\u00fc\u00e7l\u00fc backend \u00e7\u00f6z\u00fcmleri geli\u015ftirin.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-13T18:02:13+00:00\" \/>\n<meta name=\"author\" content=\"Fatih Soysal\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fatih Soysal\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"21 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler\",\"datePublished\":\"2025-10-13T18:02:13+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/\"},\"wordCount\":4305,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/#respond\"]}],\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/\",\"name\":\"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2025-10-13T18:02:13+00:00\",\"description\":\"Bir Django projesinde Class-Based Views (CBV) kullanarak verimli ve \u00f6l\u00e7eklenebilir API'ler nas\u0131l olu\u015fturulur? Frontend ile sorunsuz entegrasyon i\u00e7in ad\u0131m ad\u0131m rehberimizle ke\u015ffedin, modern web uygulamalar\u0131n\u0131z i\u00e7in g\u00fc\u00e7l\u00fc backend \u00e7\u00f6z\u00fcmleri geli\u015ftirin.\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/\",\"name\":\"Fatihsoysal.com\",\"description\":\"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim\",\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\",\"name\":\"Fatih Soysal\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"contentUrl\":\"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png\",\"width\":512,\"height\":512,\"caption\":\"Fatih Soysal\"},\"logo\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/\"},\"description\":\"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler","description":"Bir Django projesinde Class-Based Views (CBV) kullanarak verimli ve \u00f6l\u00e7eklenebilir API'ler nas\u0131l olu\u015fturulur? Frontend ile sorunsuz entegrasyon i\u00e7in ad\u0131m ad\u0131m rehberimizle ke\u015ffedin, modern web uygulamalar\u0131n\u0131z i\u00e7in g\u00fc\u00e7l\u00fc backend \u00e7\u00f6z\u00fcmleri geli\u015ftirin.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/","og_locale":"tr_TR","og_type":"article","og_title":"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler","og_description":"Bir Django projesinde Class-Based Views (CBV) kullanarak verimli ve \u00f6l\u00e7eklenebilir API'ler nas\u0131l olu\u015fturulur? Frontend ile sorunsuz entegrasyon i\u00e7in ad\u0131m ad\u0131m rehberimizle ke\u015ffedin, modern web uygulamalar\u0131n\u0131z i\u00e7in g\u00fc\u00e7l\u00fc backend \u00e7\u00f6z\u00fcmleri geli\u015ftirin.","og_url":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2025-10-13T18:02:13+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"21 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler","datePublished":"2025-10-13T18:02:13+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/"},"wordCount":4305,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/#respond"]}],"copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/","url":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/","name":"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2025-10-13T18:02:13+00:00","description":"Bir Django projesinde Class-Based Views (CBV) kullanarak verimli ve \u00f6l\u00e7eklenebilir API'ler nas\u0131l olu\u015fturulur? Frontend ile sorunsuz entegrasyon i\u00e7in ad\u0131m ad\u0131m rehberimizle ke\u015ffedin, modern web uygulamalar\u0131n\u0131z i\u00e7in g\u00fc\u00e7l\u00fc backend \u00e7\u00f6z\u00fcmleri geli\u015ftirin.","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/django-cbv-ile-api-gelistirme-frontend-icin-guclu-cozumler\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Django CBV ile API Geli\u015ftirme: Frontend \u0130\u00e7in G\u00fc\u00e7l\u00fc \u00c7\u00f6z\u00fcmler"}]},{"@type":"WebSite","@id":"https:\/\/fatihsoysal.com\/blog\/#website","url":"https:\/\/fatihsoysal.com\/blog\/","name":"Fatihsoysal.com","description":"Blog - Yaz\u0131l\u0131m D\u00fcnyas\u0131 Tecr\u00fcbelerim","publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/fatihsoysal.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1","name":"Fatih Soysal","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","contentUrl":"https:\/\/fatihsoysal.com\/blog\/wp-content\/uploads\/2024\/04\/cropped-replicate-prediction-3kgg1hgjn5rgp0cf0p5tr0jw7w-1.png","width":512,"height":512,"caption":"Fatih Soysal"},"logo":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/image\/"},"description":"Kullan\u0131m ve kodlama m\u00fckemmeliyetini odak alan uygulamalar olu\u015fturma deneyimine sahip, profesyonel olarak 15+ y\u0131l \u00fczeri deneyime sahip bir yaz\u0131l\u0131m m\u00fchendisi.","url":"https:\/\/fatihsoysal.com\/blog\/author\/fatihsoysal\/"}]}},"yoast_meta":{"yoast_wpseo_title":"","yoast_wpseo_metadesc":"","yoast_wpseo_canonical":""},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/31772","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/comments?post=31772"}],"version-history":[{"count":0,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/31772\/revisions"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=31772"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=31772"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=31772"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}