{"id":42137,"date":"2026-05-28T09:11:34","date_gmt":"2026-05-28T06:11:34","guid":{"rendered":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/"},"modified":"2026-05-28T09:12:09","modified_gmt":"2026-05-28T06:12:09","slug":"django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim","status":"publish","type":"post","link":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/","title":{"rendered":"Django Admin&#8217;e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim?"},"content":{"rendered":"<h2>Django Admin&#8217;e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim?<\/h2>\n<p>Django y\u00f6netim panelinizdeki statik veriler sizi yoruyor ve anl\u0131k kararlar alman\u0131z\u0131 engelliyor mu? \u0130\u015f zekas\u0131 (Business Intelligence) ara\u00e7lar\u0131na yat\u0131r\u0131m yapmadan veya karma\u015f\u0131k \u00fc\u00e7\u00fcnc\u00fc taraf entegrasyonlar\u0131na girmeden, verilerinizi anl\u0131k olarak g\u00f6rselle\u015ftirmek mi istiyorsunuz? Bu makalede, herhangi bir ek Python paketi kurmaya gerek kalmadan, sadece Django&#8217;nun kendi yeteneklerini ve modern web teknolojilerini kullanarak, canl\u0131 ve dinamik grafikler eklemenin t\u00fcm ad\u0131mlar\u0131n\u0131 ke\u015ffedece\u011fiz. Art\u0131k verilerinizle daha interaktif bir ili\u015fki kurarak i\u015f s\u00fcre\u00e7lerinizi anl\u0131k olarak takip edebileceksiniz.<\/p>\n<p>Pek \u00e7ok geli\u015ftirici, Django Admin panelinin sundu\u011fu esnekli\u011fi ve g\u00fcc\u00fc takdir eder. Ancak, varsay\u0131lan olarak sunulan veri g\u00f6r\u00fcnt\u00fcleme y\u00f6ntemleri genellikle statiktir ve anl\u0131k analizler i\u00e7in yetersiz kalabilir. \u00d6zellikle b\u00fcy\u00fck veri setleriyle \u00e7al\u0131\u015f\u0131rken veya h\u0131zl\u0131 de\u011fi\u015fen i\u015f metriklerini izlerken, dinamik ve canl\u0131 grafikler vazge\u00e7ilmez bir ihtiya\u00e7 haline gelir. Bu rehber, size bu ihtiyac\u0131 nas\u0131l kar\u015f\u0131layaca\u011f\u0131n\u0131z\u0131, \u00fcstelik projenize tek bir yeni Python ba\u011f\u0131ml\u0131l\u0131\u011f\u0131 eklemeden nas\u0131l ba\u015faraca\u011f\u0131n\u0131z\u0131 ad\u0131m ad\u0131m g\u00f6sterecek.<\/p>\n<h3>Neden Harici Paket Kullanmadan Bu \u0130\u015fi \u00c7\u00f6zmeliyiz?<\/h3>\n<p>Bir\u00e7ok durumda, bir problemi \u00e7\u00f6zmek i\u00e7in hemen yeni bir k\u00fct\u00fcphane veya paket kurma e\u011filiminde oluruz. Ancak bu yakla\u015f\u0131m\u0131n uzun vadede baz\u0131 dezavantajlar\u0131 olabilir. Django Admin paneline canl\u0131 grafikler eklemek s\u00f6z konusu oldu\u011funda, harici paket kullanmaman\u0131n birden fazla \u00f6nemli faydas\u0131 bulunmaktad\u0131r. \u0130lk olarak, projenizin ba\u011f\u0131ml\u0131l\u0131k (dependency) say\u0131s\u0131n\u0131 azalt\u0131rs\u0131n\u0131z. Daha az ba\u011f\u0131ml\u0131l\u0131k, daha az bak\u0131m y\u00fck\u00fc, daha az g\u00fcvenlik a\u00e7\u0131\u011f\u0131 riski ve daha sorunsuz g\u00fcncellemeler anlam\u0131na gelir. Her yeni paket, potansiyel bir uyumluluk sorununu veya gelecekteki bir g\u00fcvenlik a\u00e7\u0131\u011f\u0131n\u0131 beraberinde getirebilir. Bu nedenle, mevcut ara\u00e7larla \u00e7\u00f6z\u00fclebilecek bir sorunu harici bir paketle \u00e7\u00f6zmek, bazen gereksiz bir karma\u015f\u0131kl\u0131k yaratabilir.<\/p>\n<p>\u0130kinci olarak, projenizin da\u011f\u0131t\u0131m (deployment) s\u00fcrecini basitle\u015ftirirsiniz. Yeni bir paket kurmak genellikle <code>pip install<\/code> komutunu \u00e7al\u0131\u015ft\u0131rmay\u0131 ve <code>requirements.txt<\/code> dosyas\u0131n\u0131 g\u00fcncellemeyi gerektirir. Bu durum, \u00f6zellikle s\u00fcrekli entegrasyon\/s\u00fcrekli teslimat (CI\/CD) s\u00fcre\u00e7lerinde ek ad\u0131mlar anlam\u0131na gelebilir. Harici paket kullanmad\u0131\u011f\u0131n\u0131zda, bu ad\u0131mlar\u0131 atlam\u0131\u015f olursunuz ve da\u011f\u0131t\u0131m s\u00fcreciniz daha h\u0131zl\u0131 ve daha az hataya a\u00e7\u0131k hale gelir. Projenin genel performans\u0131na da olumlu yans\u0131malar\u0131 olabilir; daha az paket, daha k\u00fc\u00e7\u00fck bir uygulama boyutu ve potansiyel olarak daha h\u0131zl\u0131 ba\u015flang\u0131\u00e7 s\u00fcreleri demektir.<\/p>\n<p>\u00dc\u00e7\u00fcnc\u00fc ve belki de en \u00f6nemli fayda, kontrol\u00fcn tamamen sizde olmas\u0131d\u0131r. Harici bir paketin sundu\u011fu \u00f6zellikler ve k\u0131s\u0131tlamalarla s\u0131n\u0131rl\u0131 kalmazs\u0131n\u0131z. Kendi \u00e7\u00f6z\u00fcm\u00fcn\u00fcz\u00fc in\u015fa etti\u011finizde, tam olarak neye ihtiyac\u0131n\u0131z varsa onu geli\u015ftirirsiniz ve bu \u00e7\u00f6z\u00fcm projenizin \u00f6zel gereksinimlerine m\u00fckemmel bir \u015fekilde uyar. G\u00f6rselle\u015ftirme \u015feklini, veri \u00e7ekme mant\u0131\u011f\u0131n\u0131 ve g\u00fcncelleme s\u0131kl\u0131\u011f\u0131n\u0131 tamamen kendi ihtiya\u00e7lar\u0131n\u0131za g\u00f6re ayarlayabilirsiniz. Bu da size daha fazla esneklik ve \u00f6zelle\u015ftirme imkan\u0131 sunar. Ayr\u0131ca, bu yakla\u015f\u0131m, web geli\u015ftirme temelleri olan HTML, CSS ve JavaScript bilginizi peki\u015ftirmenize de yard\u0131mc\u0131 olur. Django&#8217;nun g\u00fc\u00e7l\u00fc arka plan (backend) yeteneklerini, modern \u00f6n y\u00fcz (frontend) teknikleriyle birle\u015ftirerek tam kapsaml\u0131 bir \u00e7\u00f6z\u00fcm \u00fcretme becerinizi geli\u015ftirirsiniz. Bu s\u00fcre\u00e7, sadece bir problem \u00e7\u00f6zmekle kalmaz, ayn\u0131 zamanda teknik bilgi birikiminizi de art\u0131r\u0131r.<\/p>\n<h3>Temelleri Anlamak: Django Admin ve Modern Web Teknolojileri<\/h3>\n<p>Django Admin, geli\u015ftiricilere veritaban\u0131 modelleri \u00fczerinde h\u0131zl\u0131 bir \u015fekilde CRUD (Create, Read, Update, Delete) i\u015flemleri yapabilecekleri, haz\u0131r bir y\u00f6netim aray\u00fcz\u00fc sunar. Bu panel, bir\u00e7ok i\u015f uygulamas\u0131 i\u00e7in ba\u015flang\u0131\u00e7 noktas\u0131 veya hatta nihai \u00e7\u00f6z\u00fcm olabilir. Ancak, varsay\u0131lan olarak sunulan aray\u00fcz, veri g\u00f6rselle\u015ftirme veya canl\u0131 raporlama gibi dinamik \u00f6zelliklerden yoksundur. \u0130\u015fte bu noktada modern web teknolojileri devreye girer. Django&#8217;nun arka plan g\u00fcc\u00fcn\u00fc, \u00f6n y\u00fczdeki (frontend) JavaScript k\u00fct\u00fcphaneleriyle birle\u015ftirerek bu eksikli\u011fi giderebiliriz.<\/p>\n<p>Django Admin panelini \u00f6zelle\u015ftirmek, asl\u0131nda Django&#8217;nun \u015fablon (template) sistemini ve statik dosya (static file) y\u00f6netimini iyi anlamaktan ge\u00e7er. Django, y\u00f6netim panelinin her bir b\u00f6l\u00fcm\u00fc i\u00e7in belirli \u015fablonlar kullan\u0131r ve bu \u015fablonlar\u0131 kendi projenizde ge\u00e7ersiz k\u0131larak (override) istedi\u011finiz de\u011fi\u015fiklikleri yapman\u0131za olanak tan\u0131r. \u00d6rne\u011fin, ana admin sayfas\u0131n\u0131 de\u011fi\u015ftirmek i\u00e7in <code>admin\/base_site.html<\/code> \u015fablonunu, belirli bir modelin listeleme sayfas\u0131n\u0131 de\u011fi\u015ftirmek i\u00e7in ise <code>admin\/change_list.html<\/code> \u015fablonunu kullanabilirsiniz. Bu, bizim canl\u0131 grafiklerimizi ekleyece\u011fimiz temel mekanizmad\u0131r.<\/p>\n<p>\u00d6n y\u00fcz taraf\u0131nda ise JavaScript, HTML ve CSS \u00fc\u00e7l\u00fcs\u00fc bizim ana ara\u00e7lar\u0131m\u0131z olacak. \u00d6zellikle JavaScript, dinamik i\u00e7erik olu\u015fturma ve verilerle etkile\u015fim kurma konusunda kilit rol oynar. Canl\u0131 grafikler i\u00e7in bir JavaScript grafik k\u00fct\u00fcphanesine ihtiyac\u0131m\u0131z olacak. Bu makalede, kullan\u0131m\u0131 kolay ve pop\u00fcler bir se\u00e7enek olan <a href=\"https:\/\/www.chartjs.org\/\">Chart.js<\/a>&#8216;i kullanaca\u011f\u0131z. Chart.js, HTML <code>&lt;canvas&gt;<\/code> elementi \u00fczerine \u00e7e\u015fitli grafik t\u00fcrlerini (\u00e7izgi, \u00e7ubuk, pasta vb.) \u00e7izmenize olanak tan\u0131r ve CDN (Content Delivery Network) \u00fczerinden kolayca projenize dahil edilebilir, b\u00f6ylece herhangi bir ek paket kurulumuna gerek kalmaz.<\/p>\n<p>Verilerin canl\u0131 olarak g\u00fcncellenmesi i\u00e7in ise AJAX (Asynchronous JavaScript and XML) teknolojisinden faydalanaca\u011f\u0131z. AJAX, bir web sayfas\u0131n\u0131n tamam\u0131n\u0131 yeniden y\u00fcklemeden, arka planda sunucuya istek g\u00f6nderip yan\u0131t almas\u0131n\u0131 sa\u011flayan bir tekniktir. Bu sayede, Django arka plan\u0131nda haz\u0131rlad\u0131\u011f\u0131m\u0131z veri u\u00e7 noktalar\u0131ndan (API endpoints) d\u00fczenli aral\u0131klarla yeni verileri \u00e7ekebilir ve bu verileri kullanarak grafiklerimizi anl\u0131k olarak g\u00fcncelleyebiliriz. Django&#8217;nun kendi URL y\u00f6nlendirme (URL routing) ve g\u00f6r\u00fcn\u00fcm (view) sistemini kullanarak, grafiklerimizin ihtiya\u00e7 duydu\u011fu JSON format\u0131ndaki verileri sunacak basit bir API ucu olu\u015fturaca\u011f\u0131z. Bu entegrasyon, Django&#8217;nun g\u00fc\u00e7l\u00fc veri i\u015fleme yeteneklerini, modern taray\u0131c\u0131lar\u0131n zengin g\u00f6rselle\u015ftirme kapasitesiyle birle\u015ftirerek, ger\u00e7ekten dinamik ve kullan\u0131c\u0131 dostu bir y\u00f6netim paneli deneyimi sunmam\u0131z\u0131 sa\u011flayacak.<\/p>\n<h3>Veri Kayna\u011f\u0131n\u0131 Haz\u0131rlamak: Django Modellerinden API U\u00e7 Noktas\u0131na<\/h3>\n<p>Canl\u0131 grafiklerin temelini, g\u00fcncel ve do\u011fru veri olu\u015fturur. Bu verileri Django modellerimizden al\u0131p, \u00f6n y\u00fczdeki JavaScript kodumuzun kolayca t\u00fcketebilece\u011fi bir formatta sunmam\u0131z gerekiyor. Bu genellikle JSON (JavaScript Object Notation) format\u0131nda bir API u\u00e7 noktas\u0131 olu\u015fturmak anlam\u0131na gelir. Django, bu t\u00fcr bir u\u00e7 nokta olu\u015fturmak i\u00e7in olduk\u00e7a esnek ve g\u00fc\u00e7l\u00fc ara\u00e7lar sunar, \u00fcstelik hi\u00e7bir ek paket kurman\u0131za gerek kalmaz.<\/p>\n<p>\u00d6ncelikle, hangi verileri g\u00f6rselle\u015ftirmek istedi\u011fimize karar vermeliyiz. Diyelim ki bir e-ticaret uygulaman\u0131z var ve g\u00fcnl\u00fck sat\u0131\u015f miktarlar\u0131n\u0131 veya belirli bir \u00fcr\u00fcn\u00fcn stok durumunu canl\u0131 olarak g\u00f6rmek istiyorsunuz. Bu veriler muhtemelen <code>Siparis<\/code> (Order) veya <code>Urun<\/code> (Product) gibi modellerinizde tutuluyordur. \u00d6rne\u011fin, son 7 g\u00fcn\u00fcn sat\u0131\u015f verilerini almak i\u00e7in \u015f\u00f6yle bir sorgu yapabiliriz:<\/p>\n<div class=\"code-container\">\n<pre><code>\n# models.py\nfrom django.db import models\n\nclass Siparis(models.Model):\n    urun = models.CharField(max_length=100)\n    miktar = models.IntegerField()\n    fiyat = models.DecimalField(max_digits=10, decimal_places=2)\n    tarih = models.DateField(auto_now_add=True)\n\n    def __str__(self):\n        return f\"Sipari\u015f #{self.id} - {self.urun}\"\n  <\/code><\/pre>\n<\/div>\n<p>\u015eimdi, bu verileri JSON format\u0131nda sunacak bir Django g\u00f6r\u00fcn\u00fcm\u00fc (view) olu\u015ftural\u0131m. Bu g\u00f6r\u00fcn\u00fcm, belirli bir zaman aral\u0131\u011f\u0131ndaki sipari\u015f verilerini i\u015fleyecek ve bir s\u00f6zl\u00fck (dictionary) listesi olarak d\u00f6nd\u00fcrecektir. Daha sonra bu s\u00f6zl\u00fck listesini <code>JsonResponse<\/code> kullanarak JSON format\u0131na d\u00f6n\u00fc\u015ft\u00fcrece\u011fiz. <code>JsonResponse<\/code>, Django&#8217;nun kendi i\u00e7inde gelen bir yard\u0131mc\u0131 fonksiyondur ve harici bir serile\u015ftirme (serialization) k\u00fct\u00fcphanesine ihtiya\u00e7 duymadan JSON yan\u0131tlar\u0131 olu\u015fturman\u0131z\u0131 sa\u011flar.<\/p>\n<div class=\"code-container\">\n<pre><code>\n# myapp\/views.py\nfrom django.http import JsonResponse\nfrom django.db.models import Sum\nfrom datetime import date, timedelta\nfrom .models import Siparis\n\ndef get_daily_sales_data(request):\n    today = date.today()\n    last_seven_days = [today - timedelta(days=i) for i in range(7)]\n    last_seven_days.reverse() # En eskiden en yeniye s\u0131rala\n\n    sales_data = []\n    for day in last_seven_days:\n        daily_total = Siparis.objects.filter(tarih=day).aggregate(total_sales=Sum('fiyat'))['total_sales']\n        sales_data.append({\n            'date': day.strftime('%Y-%m-%d'),\n            'total_sales': float(daily_total) if daily_total else 0\n        })\n\n    return JsonResponse({'sales': sales_data})\n  <\/code><\/pre>\n<\/div>\n<p>Bu g\u00f6r\u00fcn\u00fcm, son yedi g\u00fcn\u00fcn her biri i\u00e7in toplam sat\u0131\u015f miktar\u0131n\u0131 hesaplar. E\u011fer belirli bir g\u00fcnde sat\u0131\u015f yoksa, toplam sat\u0131\u015f miktar\u0131n\u0131 s\u0131f\u0131r olarak d\u00f6nd\u00fcr\u00fcr. Verileri <code>date<\/code> ve <code>total_sales<\/code> anahtarlar\u0131yla bir liste i\u00e7inde paketleyerek JSON olarak sunar. <code>float(daily_total)<\/code> d\u00f6n\u00fc\u015f\u00fcm\u00fc, <code>Decimal<\/code> tipinin do\u011frudan JSON&#8217;a serile\u015ftirilememesi sorununu \u00e7\u00f6zer.<\/p>\n<p>Son olarak, bu g\u00f6r\u00fcn\u00fcm\u00fc bir URL ile ili\u015fkilendirmemiz gerekiyor. Bu URL, \u00f6n y\u00fczdeki JavaScript kodumuzun veri \u00e7ekmek i\u00e7in kullanaca\u011f\u0131 adres olacakt\u0131r. Bu URL&#8217;yi Django Admin panelinin URL&#8217;lerinden ayr\u0131, kendi uygulaman\u0131z\u0131n <code>urls.py<\/code> dosyas\u0131na ekleyebilirsiniz:<\/p>\n<div class=\"code-container\">\n<pre><code>\n# myapp\/urls.py\nfrom django.urls import path\nfrom . import views\n\nurlpatterns = [\n    path('api\/daily-sales\/', views.get_daily_sales_data, name='daily_sales_api'),\n]\n  <\/code><\/pre>\n<\/div>\n<p>Ana projenizin <code>urls.py<\/code> dosyas\u0131na da bu uygulamay\u0131 dahil etmeyi unutmay\u0131n:<\/p>\n<div class=\"code-container\">\n<pre><code>\n# myproject\/urls.py\nfrom django.contrib import admin\nfrom django.urls import path, include\n\nurlpatterns = [\n    path('admin\/', admin.site.urls),\n    path('myapp\/', include('myapp.urls')), # Uygulaman\u0131z\u0131n URL'lerini dahil edin\n]\n  <\/code><\/pre>\n<\/div>\n<p>Art\u0131k <code>\/myapp\/api\/daily-sales\/<\/code> adresine bir HTTP iste\u011fi g\u00f6nderdi\u011finizde, son yedi g\u00fcn\u00fcn sat\u0131\u015f verilerini i\u00e7eren bir JSON yan\u0131t\u0131 alacaks\u0131n\u0131z. Bu veri kayna\u011f\u0131, canl\u0131 grafiklerimizi beslemek i\u00e7in haz\u0131r hale gelmi\u015f oldu. Bu yakla\u015f\u0131m, veritaban\u0131ndan \u00e7ekilen karma\u015f\u0131k verileri bile kolayca i\u015fleyip, \u00f6n y\u00fcz i\u00e7in sade ve anla\u015f\u0131l\u0131r bir formata d\u00f6n\u00fc\u015ft\u00fcrmenin temelini olu\u015fturur. Bu sayede, grafiklerinizin her zaman g\u00fcncel ve do\u011fru bilgileri yans\u0131tmas\u0131n\u0131 sa\u011flars\u0131n\u0131z.<\/p>\n<h3>G\u00f6rselle\u015ftirmenin Kalbi: JavaScript ve Chart.js<\/h3>\n<p>Veri kayna\u011f\u0131m\u0131z\u0131 Django arka plan\u0131nda haz\u0131rlad\u0131ktan sonra, s\u0131ra bu verileri kullan\u0131c\u0131ya g\u00f6rsel olarak sunmaya geldi. Bu noktada, \u00f6n y\u00fczdeki (frontend) JavaScript ve bir grafik k\u00fct\u00fcphanesi devreye giriyor. Daha \u00f6nce de belirtti\u011fimiz gibi, herhangi bir Python paketi kurmayaca\u011f\u0131m\u0131z i\u00e7in, grafik \u00e7izimini tamamen istemci taraf\u0131nda (client-side) ger\u00e7ekle\u015ftirece\u011fiz. Bu i\u015f i\u00e7in <a href=\"https:\/\/www.chartjs.org\/\">Chart.js<\/a>, basitli\u011fi, esnekli\u011fi ve CDN \u00fczerinden kolayca entegre edilebilir olmas\u0131 nedeniyle m\u00fckemmel bir se\u00e7imdir.<\/p>\n<p>Chart.js, HTML <code>&lt;canvas&gt;<\/code> elementi \u00fczerine \u00e7e\u015fitli interaktif ve duyarl\u0131 (responsive) grafikler \u00e7izmenize olanak tan\u0131r. \u00c7ubuk grafikler, \u00e7izgi grafikler, pasta grafikler ve daha fazlas\u0131n\u0131 destekler. En g\u00fczeli de, do\u011frudan bir CDN&#8217;den y\u00fcklenebilir olmas\u0131, projenize herhangi bir Node.js veya npm ba\u011f\u0131ml\u0131l\u0131\u011f\u0131 eklemenizi gerektirmez. Bu, bizim &#8220;tek bir paket bile kurmadan&#8221; hedefimize m\u00fckemmel bir \u015fekilde uyan bir yakla\u015f\u0131md\u0131r.<\/p>\n<p>\u0130lk ad\u0131m olarak, grafiklerimizi yerle\u015ftirece\u011fimiz bir HTML <code>&lt;canvas&gt;<\/code> elementine ihtiyac\u0131m\u0131z var. Bu element, Chart.js&#8217;in grafi\u011fi \u00e7izece\u011fi tuval g\u00f6revi g\u00f6recektir. Daha sonra, bu canvas elementini hedef alarak JavaScript ile Chart.js&#8217;i ba\u015flataca\u011f\u0131z. \u00d6rnek bir \u00e7izgi grafik olu\u015fturmak i\u00e7in temel yap\u0131 \u015fu \u015fekildedir:<\/p>\n<div class=\"code-container\">\n<pre><code>\n&lt;!-- HTML B\u00f6l\u00fcm\u00fc --&gt;\n&lt;canvas id=\"mySalesChart\"&gt;&lt;\/canvas&gt;\n\n&lt;!-- JavaScript B\u00f6l\u00fcm\u00fc --&gt;\n&lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"&gt;&lt;\/script&gt;\n&lt;script&gt;\n  \/\/ \u00d6rnek statik veri\n  const labels = ['Ocak', '\u015eubat', 'Mart', 'Nisan', 'May\u0131s', 'Haziran', 'Temmuz'];\n  const data = {\n    labels: labels,\n    datasets: [{\n      label: 'Ayl\u0131k Sat\u0131\u015flar',\n      backgroundColor: 'rgb(75, 192, 192)',\n      borderColor: 'rgb(75, 192, 192)',\n      data: [0, 10, 5, 2, 20, 30, 45],\n    }]\n  };\n\n  const config = {\n    type: 'line',\n    data: data,\n    options: {}\n  };\n\n  \/\/ Grafi\u011fi \u00e7iz\n  const myChart = new Chart(\n    document.getElementById('mySalesChart'),\n    config\n  );\n&lt;\/script&gt;\n  <\/code><\/pre>\n<\/div>\n<p>Yukar\u0131daki \u00f6rnekte, \u00f6nce Chart.js k\u00fct\u00fcphanesini CDN&#8217;den y\u00fckl\u00fcyoruz. Ard\u0131ndan, bir <code>&lt;canvas&gt;<\/code> elementi tan\u0131ml\u0131yor ve JavaScript kodu i\u00e7inde bu canvas&#8217;\u0131 hedef alarak yeni bir Chart.js \u00f6rne\u011fi olu\u015fturuyoruz. <code>labels<\/code> dizisi X ekseni etiketlerini, <code>datasets<\/code> ise grafikte g\u00f6sterilecek veri serilerini (veri k\u00fcmelerini) i\u00e7erir. Her bir veri k\u00fcmesi, bir etiket, renkler ve ger\u00e7ek veri noktalar\u0131ndan olu\u015fur. <code>config<\/code> nesnesi, grafi\u011fin t\u00fcr\u00fcn\u00fc (\u00f6rne\u011fin, <code>'line'<\/code> veya <code>'bar'<\/code>) ve veri ile se\u00e7eneklerini belirler.<\/p>\n<p>Bu statik \u00f6rnek, Chart.js&#8217;in nas\u0131l \u00e7al\u0131\u015ft\u0131\u011f\u0131na dair temel bir fikir verir. Ancak bizim amac\u0131m\u0131z canl\u0131 grafikler oldu\u011fu i\u00e7in, bu statik verileri daha \u00f6nce olu\u015fturdu\u011fumuz Django API u\u00e7 noktas\u0131ndan \u00e7ekece\u011fimiz dinamik verilerle de\u011fi\u015ftirmemiz gerekecek. Bu, AJAX istekleri ve Chart.js&#8217;in veri g\u00fcncelleme mekanizmalar\u0131 kullan\u0131larak yap\u0131lacakt\u0131r. JavaScript&#8217;in <code>fetch()<\/code> API&#8217;si veya eski taray\u0131c\u0131lar i\u00e7in <code>XMLHttpRequest<\/code> gibi ara\u00e7larla sunucuya istek at\u0131p, d\u00f6nen JSON verisini Chart.js grafi\u011fimize entegre edece\u011fiz.<\/p>\n<p>Bir sonraki ad\u0131mda, bu Chart.js kodunu Django Admin paneline nas\u0131l entegre edece\u011fimizi ve verileri dinamik olarak nas\u0131l \u00e7ekece\u011fimizi detayland\u0131raca\u011f\u0131z. Buradaki ana fikir, HTML ve JavaScript&#8217;in g\u00fcc\u00fcn\u00fc kullanarak, arka plandaki veri kayna\u011f\u0131ndan ba\u011f\u0131ms\u0131z olarak zengin ve interaktif bir \u00f6n y\u00fcz deneyimi sunmakt\u0131r. Bu yakla\u015f\u0131m, Django Admin&#8217;i sadece bir veri giri\u015f paneli olmaktan \u00e7\u0131kar\u0131p, ger\u00e7ek zamanl\u0131 i\u015f zekas\u0131 paneline d\u00f6n\u00fc\u015ft\u00fcrmenin kap\u0131lar\u0131n\u0131 aralar.<\/p>\n<h3>Django Admin \u015eablonlar\u0131n\u0131 Geni\u015fletmek: Kendi Grafi\u011fimizi Entegre Etmek<\/h3>\n<p>Django Admin&#8217;e \u00f6zel grafiklerimizi eklemenin en uygun yolu, Django&#8217;nun kendi \u015fablon sistemini kullanarak Admin panelinin \u015fablonlar\u0131n\u0131 geni\u015fletmek (extend) veya ge\u00e7ersiz k\u0131lmak (override) olacakt\u0131r. Bu y\u00f6ntem, Admin panelinin genel g\u00f6r\u00fcn\u00fcm\u00fcn\u00fc ve i\u015flevselli\u011fini bozmadan kendi \u00f6zel i\u00e7eri\u011fimizi eklememizi sa\u011flar. Genellikle, t\u00fcm Admin paneline etki etmek i\u00e7in <code>admin\/base_site.html<\/code> \u015fablonunu veya belirli bir modelin listeleme veya detay sayfas\u0131na eklemek i\u00e7in <code>admin\/change_list.html<\/code> ya da <code>admin\/change_form.html<\/code> \u015fablonlar\u0131n\u0131 hedef al\u0131r\u0131z.<\/p>\n<p>Bu \u00f6rnekte, ana Admin panelinin ana sayfas\u0131nda (dashboard) bir grafik g\u00f6stermek istedi\u011fimizi varsayal\u0131m. Bunun i\u00e7in <code>admin\/base_site.html<\/code> \u015fablonunu geni\u015fletmek en mant\u0131kl\u0131 yakla\u015f\u0131m olacakt\u0131r. \u0130lk olarak, projenizin ana dizininde (veya bir uygulaman\u0131z\u0131n i\u00e7inde) <code>templates\/admin<\/code> ad\u0131nda bir klas\u00f6r olu\u015fturman\u0131z gerekir. Django, bu klas\u00f6rdeki \u015fablonlar\u0131, kendi Admin \u015fablonlar\u0131ndan \u00f6nce arayacakt\u0131r.<\/p>\n<div class=\"code-container\">\n<pre><code>\n# Proje dizini yap\u0131s\u0131\nmyproject\/\n\u251c\u2500\u2500 myproject\/\n\u2502   \u251c\u2500\u2500 settings.py\n\u2502   \u2514\u2500\u2500 urls.py\n\u251c\u2500\u2500 myapp\/\n\u2502   \u251c\u2500\u2500 models.py\n\u2502   \u251c\u2500\u2500 views.py\n\u2502   \u2514\u2500\u2500 urls.py\n\u2514\u2500\u2500 templates\/\n    \u2514\u2500\u2500 admin\/\n        \u2514\u2500\u2500 base_site.html  &lt;-- Buraya ekleyece\u011fiz\n  <\/code><\/pre>\n<\/div>\n<p><code>base_site.html<\/code> dosyas\u0131n\u0131 olu\u015fturduktan sonra, Django&#8217;nun orijinal <code>base_site.html<\/code> \u015fablonunu geni\u015fletmemiz ve kendi i\u00e7eri\u011fimizi uygun bir blo\u011fa eklememiz gerekiyor. Genellikle <code>{% block content %}<\/code> blo\u011fu, ana i\u00e7eri\u011fi yerle\u015ftirmek i\u00e7in idealdir. Ayr\u0131ca, Chart.js k\u00fct\u00fcphanesini ve kendi JavaScript kodumuzu da bu \u015fablona dahil etmeliyiz.<\/p>\n<div class=\"code-container\">\n<pre><code>\n&lt;!-- templates\/admin\/base_site.html --&gt;\n{% extends \"admin\/base.html\" %}\n{% load static %}\n\n{% block extrahead %}\n  &lt;!-- Chart.js k\u00fct\u00fcphanesini CDN'den y\u00fckle --&gt;\n  &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"&gt;&lt;\/script&gt;\n{% endblock %}\n\n{% block content %}\n  {{ block.super }} &lt;!-- Orijinal admin i\u00e7eri\u011fini koru --&gt;\n\n  &lt;div style=\"margin: 20px;\"&gt; &lt;!-- Grafi\u011fi biraz bo\u015flukla yerle\u015ftir --&gt;\n    &lt;h3&gt;Son 7 G\u00fcnl\u00fck Sat\u0131\u015f Grafi\u011fi&lt;\/h3&gt;\n    &lt;div class=\"chart-container\" style=\"position: relative; height:40vh; width:80vw\"&gt;\n      &lt;canvas id=\"dailySalesChart\"&gt;&lt;\/canvas&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n\n  &lt;script&gt;\n    document.addEventListener('DOMContentLoaded', function() {\n      const ctx = document.getElementById('dailySalesChart').getContext('2d');\n      let salesChart; \/\/ Grafik nesnesini d\u0131\u015far\u0131da tan\u0131mla\n\n      function fetchSalesData() {\n        fetch('\/myapp\/api\/daily-sales\/') \/\/ Daha \u00f6nce olu\u015fturdu\u011fumuz API u\u00e7 noktas\u0131\n          .then(response => response.json())\n          .then(data => {\n            const labels = data.sales.map(item => item.date);\n            const salesAmounts = data.sales.map(item => item.total_sales);\n\n            if (salesChart) {\n              \/\/ Grafik zaten varsa veriyi g\u00fcncelle\n              salesChart.data.labels = labels;\n              salesChart.data.datasets[0].data = salesAmounts;\n              salesChart.update();\n            } else {\n              \/\/ Grafik yoksa yeni olu\u015ftur\n              salesChart = new Chart(ctx, {\n                type: 'line',\n                data: {\n                  labels: labels,\n                  datasets: [{\n                    label: 'Toplam Sat\u0131\u015f (\u20ba)',\n                    data: salesAmounts,\n                    backgroundColor: 'rgba(75, 192, 192, 0.2)',\n                    borderColor: 'rgba(75, 192, 192, 1)',\n                    borderWidth: 1,\n                    fill: true\n                  }]\n                },\n                options: {\n                  responsive: true,\n                  maintainAspectRatio: false,\n                  scales: {\n                    y: {\n                      beginAtZero: true,\n                      title: {\n                        display: true,\n                        text: 'Sat\u0131\u015f Miktar\u0131'\n                      }\n                    },\n                    x: {\n                        title: {\n                            display: true,\n                            text: 'Tarih'\n                        }\n                    }\n                  }\n                }\n              });\n            }\n          })\n          .catch(error => console.error('Sat\u0131\u015f verileri \u00e7ekilirken hata olu\u015ftu:', error));\n      }\n\n      \/\/ Sayfa y\u00fcklendi\u011finde veriyi \u00e7ek ve grafi\u011fi olu\u015ftur\n      fetchSalesData();\n\n      \/\/ \u0130ste\u011fe ba\u011fl\u0131: Grafi\u011fi belirli aral\u0131klarla g\u00fcncelle (\u00f6rn: her 30 saniyede bir)\n      \/\/ setInterval(fetchSalesData, 30000);\n    });\n  &lt;\/script&gt;\n{% endblock %}\n  <\/code><\/pre>\n<\/div>\n<p>Bu kod blo\u011funda dikkat etmemiz gereken birka\u00e7 \u00f6nemli nokta var:<\/p>\n<ul>\n<li><code>{% extends \"admin\/base.html\" %}<\/code>: Admin panelinin temel \u015fablonunu geni\u015fletti\u011fimizi belirtir.<\/li>\n<li><code>{% block extrahead %}<\/code>: Buraya Chart.js CDN ba\u011flant\u0131s\u0131n\u0131 ekledik. Bu, k\u00fct\u00fcphanenin sayfa ba\u015fl\u0131\u011f\u0131nda (head) y\u00fcklenmesini sa\u011flar.<\/li>\n<li><code>{% block content %}<\/code>: Bu blok i\u00e7ine kendi HTML i\u00e7eri\u011fimizi (<code>&lt;canvas&gt;<\/code> elementi) ve JavaScript kodumuzu yerle\u015ftirdik. <code>{{ block.super }}<\/code> ifadesi, orijinal <code>content<\/code> blo\u011funun i\u00e7eri\u011finin de korunmas\u0131n\u0131 sa\u011flar.<\/li>\n<li><code>&lt;div class=\"chart-container\"&gt;<\/code>: Grafi\u011fimiz i\u00e7in bir kapsay\u0131c\u0131 div olu\u015fturduk ve CSS ile boyutlar\u0131n\u0131 ayarlad\u0131k.<\/li>\n<li><code>fetchSalesData()<\/code> fonksiyonu: Bu fonksiyon, daha \u00f6nce olu\u015fturdu\u011fumuz <code>\/myapp\/api\/daily-sales\/<\/code> API u\u00e7 noktas\u0131ndan verileri \u00e7eker.<\/li>\n<li><code>Chart(ctx, config)<\/code>: \u00c7ekilen verilerle yeni bir Chart.js grafi\u011fi olu\u015fturur veya mevcut grafi\u011fi g\u00fcnceller. <code>if (salesChart)<\/code> kontrol\u00fc, grafi\u011fin zaten var olup olmad\u0131\u011f\u0131n\u0131 kontrol ederek, tekrar tekrar yeni grafik olu\u015fturmak yerine mevcut grafi\u011fi g\u00fcncellememizi sa\u011flar, bu da performans i\u00e7in \u00f6nemlidir.<\/li>\n<li><code>document.addEventListener('DOMContentLoaded', ...)<\/code>: Bu, sayfa tamamen y\u00fcklendi\u011finde JavaScript kodunun \u00e7al\u0131\u015fmas\u0131n\u0131 garanti eder.<\/li>\n<\/ul>\n<p>Bu entegrasyon sayesinde, Django Admin panelinize giri\u015f yapt\u0131\u011f\u0131n\u0131zda, ana sayfan\u0131zda canl\u0131 sat\u0131\u015f grafiklerinizi g\u00f6receksiniz. Bu, hem y\u00f6neticilere anl\u0131k bilgi ak\u0131\u015f\u0131 sa\u011flar hem de Admin panelinin i\u015flevselli\u011fini \u00f6nemli \u00f6l\u00e7\u00fcde art\u0131r\u0131r. Bu yakla\u015f\u0131m, sadece ana sayfayla s\u0131n\u0131rl\u0131 kalmay\u0131p, belirli modelin listeleme sayfalar\u0131na da benzer \u015fekilde grafikler eklemenizi sa\u011flayabilir, bu da \u00f6zelle\u015ftirme i\u00e7in geni\u015f bir alan sunar.<\/p>\n<h3>Canl\u0131 G\u00fcncellemeler: AJAX ile Dinamik Veri Ak\u0131\u015f\u0131<\/h3>\n<p>Grafi\u011fimizi Django Admin paneline entegre ettik ve ba\u015flang\u0131\u00e7 verilerini ba\u015far\u0131yla \u00e7ektik. Ancak, &#8220;canl\u0131 grafikler&#8221; hedefimiz i\u00e7in, verilerin belirli aral\u0131klarla otomatik olarak g\u00fcncellenmesi gerekiyor. \u0130\u015fte bu noktada AJAX (Asynchronous JavaScript and XML) ve JavaScript&#8217;in zamanlama fonksiyonlar\u0131 devreye giriyor. AJAX, sayfan\u0131n tamam\u0131n\u0131 yeniden y\u00fcklemeden, arka planda sunucuya istek g\u00f6nderip yeni verileri \u00e7ekmemizi sa\u011flar. Bu sayede, kullan\u0131c\u0131 aray\u00fcz\u00fc kesintiye u\u011framadan grafiklerimiz s\u00fcrekli g\u00fcncel kalabilir.<\/p>\n<p>Daha \u00f6nceki ad\u0131mda olu\u015fturdu\u011fumuz <code>fetchSalesData()<\/code> fonksiyonu, asl\u0131nda zaten bir AJAX iste\u011fi (<code>fetch('\/myapp\/api\/daily-sales\/')<\/code>) kullan\u0131yordu. \u015eimdi yapmam\u0131z gereken, bu fonksiyonu d\u00fczenli aral\u0131klarla otomatik olarak \u00e7a\u011f\u0131rmak. Bunun i\u00e7in JavaScript&#8217;in <code>setInterval()<\/code> fonksiyonunu kullanabiliriz. <code>setInterval()<\/code>, belirli bir kodu veya fonksiyonu belirli bir milisaniye aral\u0131\u011f\u0131yla tekrar tekrar \u00e7al\u0131\u015ft\u0131rman\u0131za olanak tan\u0131r.<\/p>\n<p>\u00d6rne\u011fin, sat\u0131\u015f grafi\u011fimizin her 30 saniyede bir g\u00fcncellenmesini istiyorsak, <code>fetchSalesData()<\/code> fonksiyonunu 30000 milisaniye aral\u0131\u011f\u0131yla \u00e7a\u011f\u0131rmam\u0131z yeterlidir. Bu kodu, daha \u00f6nce <code>templates\/admin\/base_site.html<\/code> i\u00e7inde yer alan JavaScript blo\u011funa ekleyece\u011fiz:<\/p>\n<div class=\"code-container\">\n<pre><code>\n&lt;!-- templates\/admin\/base_site.html i\u00e7indeki &lt;script&gt; blo\u011fu --&gt;\n&lt;script&gt;\n    document.addEventListener('DOMContentLoaded', function() {\n      const ctx = document.getElementById('dailySalesChart').getContext('2d');\n      let salesChart;\n\n      function fetchSalesData() {\n        fetch('\/myapp\/api\/daily-sales\/')\n          .then(response => {\n            if (!response.ok) {\n              throw new Error(<code>HTTP hata! Durum: ${response.status}<\/code>);\n            }\n            return response.json();\n          })\n          .then(data => {\n            const labels = data.sales.map(item => item.date);\n            const salesAmounts = data.sales.map(item => item.total_sales);\n\n            if (salesChart) {\n              \/\/ Mevcut grafi\u011fi g\u00fcncelle\n              salesChart.data.labels = labels;\n              salesChart.data.datasets[0].data = salesAmounts;\n              salesChart.update(); \/\/ Grafi\u011fi yeniden \u00e7iz\n            } else {\n              \/\/ \u0130lk kez grafi\u011fi olu\u015ftur\n              salesChart = new Chart(ctx, {\n                type: 'line',\n                data: {\n                  labels: labels,\n                  datasets: [{\n                    label: 'Toplam Sat\u0131\u015f (\u20ba)',\n                    data: salesAmounts,\n                    backgroundColor: 'rgba(75, 192, 192, 0.2)',\n                    borderColor: 'rgba(75, 192, 192, 1)',\n                    borderWidth: 1,\n                    fill: true\n                  }]\n                },\n                options: {\n                  responsive: true,\n                  maintainAspectRatio: false,\n                  scales: {\n                    y: {\n                      beginAtZero: true,\n                      title: {\n                        display: true,\n                        text: 'Sat\u0131\u015f Miktar\u0131'\n                      }\n                    },\n                    x: {\n                        title: {\n                            display: true,\n                            text: 'Tarih'\n                        }\n                    }\n                  }\n                }\n              });\n            }\n          })\n          .catch(error => console.error('Sat\u0131\u015f verileri \u00e7ekilirken hata olu\u015ftu:', error));\n      }\n\n      \/\/ Sayfa y\u00fcklendi\u011finde ilk veriyi \u00e7ek ve grafi\u011fi olu\u015ftur\n      fetchSalesData();\n\n      \/\/ Her 30 saniyede bir veriyi \u00e7ekip grafi\u011fi g\u00fcncelle\n      setInterval(fetchSalesData, 30000); \/\/ 30000 milisaniye = 30 saniye\n    });\n&lt;\/script&gt;\n  <\/code><\/pre>\n<\/div>\n<p>Bu k\u00fc\u00e7\u00fck ekleme ile grafi\u011fimiz art\u0131k ger\u00e7ek anlamda &#8220;canl\u0131&#8221; hale gelmi\u015f oluyor. Her 30 saniyede bir, Django arka plan\u0131ndaki API u\u00e7 noktam\u0131zdan en g\u00fcncel sat\u0131\u015f verilerini \u00e7ekiyor ve Chart.js bu yeni verilerle grafi\u011fi otomatik olarak g\u00fcncelliyor. Kullan\u0131c\u0131, sayfay\u0131 yenilemeye gerek kalmadan, verilerdeki de\u011fi\u015fiklikleri an\u0131nda g\u00f6rebiliyor. Bu, \u00f6zellikle anl\u0131k takip gerektiren metrikler (\u00f6rne\u011fin, sunucu y\u00fck\u00fc, anl\u0131k ziyaret\u00e7i say\u0131s\u0131, stok de\u011fi\u015fimleri) i\u00e7in kritik \u00f6neme sahiptir.<\/p>\n<p>G\u00fcncelleme aral\u0131\u011f\u0131n\u0131 (<code>30000<\/code> de\u011feri) uygulaman\u0131z\u0131n ihtiya\u00e7lar\u0131na g\u00f6re ayarlayabilirsiniz. \u00c7ok s\u0131k g\u00fcncelleme yapmak sunucuya gereksiz y\u00fck bindirebilirken, \u00e7ok seyrek g\u00fcncelleme yapmak verilerin g\u00fcncelli\u011fini kaybetmesine neden olabilir. Optimum dengeyi bulmak \u00f6nemlidir. Ayr\u0131ca, kullan\u0131c\u0131n\u0131n sayfadan ayr\u0131ld\u0131\u011f\u0131nda veya Admin panelini kapatt\u0131\u011f\u0131nda bu interval&#8217;in temizlenmesi (<code>clearInterval()<\/code> ile) iyi bir pratik olabilir, ancak Admin panelinin do\u011fas\u0131 gere\u011fi bu genellikle gerekli de\u011fildir \u00e7\u00fcnk\u00fc kullan\u0131c\u0131 sayfadan ayr\u0131ld\u0131\u011f\u0131nda t\u00fcm JavaScript y\u00fcr\u00fctmesi durur.<\/p>\n<p>Bu dinamik veri ak\u0131\u015f\u0131, Django Admin panelini pasif bir veri g\u00f6r\u00fcnt\u00fcleme arac\u0131ndan, aktif bir i\u015f zekas\u0131 paneline d\u00f6n\u00fc\u015ft\u00fcren temel mekanizmad\u0131r. Kullan\u0131c\u0131lar, verilerin nas\u0131l de\u011fi\u015fti\u011fini zaman i\u00e7inde g\u00f6zlemleyebilir ve bu bilgilere dayanarak daha bilin\u00e7li kararlar alabilirler. Ayr\u0131ca, bu yakla\u015f\u0131m sayesinde, farkl\u0131 metrikler i\u00e7in birden fazla grafik olu\u015fturup, her birini kendi API u\u00e7 noktas\u0131 ve g\u00fcncelleme aral\u0131\u011f\u0131yla besleyerek kapsaml\u0131 bir dashboard (kontrol paneli) olu\u015fturman\u0131z da m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<h3>Ger\u00e7ek D\u00fcnya Senaryosu: E-ticaret Sitesi Sat\u0131\u015f Grafikleri<\/h3>\n<p>\u015eimdiye kadar \u00f6\u011frendiklerimizi bir araya getirerek, ger\u00e7ek bir e-ticaret sitesi senaryosunda g\u00fcnl\u00fck sat\u0131\u015f gelirlerini g\u00f6steren canl\u0131 bir grafik olu\u015ftural\u0131m. Bu vaka analizi, ad\u0131mlar\u0131 somutla\u015ft\u0131racak ve \u00f6\u011frendiklerimizi peki\u015ftirecek.<\/p>\n<p><strong>Senaryo:<\/strong> Bir online ma\u011fazan\u0131n y\u00f6neticisi, Django Admin paneline girdi\u011finde, son 7 g\u00fcn\u00fcn toplam sat\u0131\u015f gelirlerini g\u00f6steren bir \u00e7izgi grafik g\u00f6rmek istiyor. Bu grafi\u011fin, g\u00fcn i\u00e7inde yap\u0131lan yeni sat\u0131\u015flarla otomatik olarak g\u00fcncellenmesi gerekiyor.<\/p>\n<p><strong>Ad\u0131m 1: Django Modellerini Olu\u015fturma<\/strong><\/p>\n<p>\u00d6ncelikle, sat\u0131\u015f verilerini tutacak bir model tan\u0131mlayal\u0131m. Basitlik ad\u0131na sadece sipari\u015f tarihi ve toplam fiyat\u0131 i\u00e7eren bir <code>Siparis<\/code> (Order) modeli yeterli olacakt\u0131r.<\/p>\n<div class=\"code-container\">\n<pre><code>\n# myapp\/models.py\nfrom django.db import models\nfrom datetime import date\n\nclass Siparis(models.Model):\n    siparis_kodu = models.CharField(max_length=50, unique=True)\n    toplam_fiyat = models.DecimalField(max_digits=10, decimal_places=2)\n    siparis_tarihi = models.DateField(default=date.today) # Varsay\u0131lan olarak bug\u00fcn\u00fcn tarihi\n\n    class Meta:\n        verbose_name = \"Sipari\u015f\"\n        verbose_name_plural = \"Sipari\u015fler\"\n        ordering = ['-siparis_tarihi']\n\n    def __str__(self):\n        return f\"Sipari\u015f {self.siparis_kodu} - {self.toplam_fiyat} TL\"\n  <\/code><\/pre>\n<\/div>\n<p>Modeli olu\u015fturduktan sonra <code>python manage.py makemigrations<\/code> ve <code>python manage.py migrate<\/code> komutlar\u0131n\u0131 \u00e7al\u0131\u015ft\u0131rarak veritaban\u0131na uygulay\u0131n.<\/p>\n<p><strong>Ad\u0131m 2: Veri API U\u00e7 Noktas\u0131n\u0131 Olu\u015fturma<\/strong><\/p>\n<p>Son 7 g\u00fcn\u00fcn g\u00fcnl\u00fck sat\u0131\u015f toplamlar\u0131n\u0131 d\u00f6nd\u00fcrecek bir g\u00f6r\u00fcn\u00fcm (view) yazal\u0131m. Bu g\u00f6r\u00fcn\u00fcm, <code>JsonResponse<\/code> kullanarak verileri JSON format\u0131nda sunacak.<\/p>\n<div class=\"code-container\">\n<pre><code>\n# myapp\/views.py\nfrom django.http import JsonResponse\nfrom django.db.models import Sum\nfrom datetime import date, timedelta\nfrom .models import Siparis\n\ndef get_daily_sales_chart_data(request):\n    today = date.today()\n    # Son 7 g\u00fcn\u00fc kapsayan tarih listesi olu\u015ftur\n    dates = [today - timedelta(days=i) for i in range(6, -1, -1)] # Eskiden yeniye do\u011fru\n\n    sales_data = []\n    for d in dates:\n        # Belirli bir tarihteki toplam sat\u0131\u015flar\u0131 bul\n        daily_total = Siparis.objects.filter(siparis_tarihi=d).aggregate(total=Sum('toplam_fiyat'))['total']\n        sales_data.append({\n            'date': d.strftime('%Y-%m-%d'),\n            'total_sales': float(daily_total) if daily_total else 0.0\n        })\n    return JsonResponse({'sales': sales_data})\n  <\/code><\/pre>\n<\/div>\n<p><strong>Ad\u0131m 3: URL Y\u00f6nlendirmesini Tan\u0131mlama<\/strong><\/p>\n<p>Olu\u015fturdu\u011fumuz g\u00f6r\u00fcn\u00fcm\u00fc bir URL ile ili\u015fkilendirelim.<\/p>\n<div class=\"code-container\">\n<pre><code>\n# myapp\/urls.py\nfrom django.urls import path\nfrom . import views\n\nurlpatterns = [\n    path('api\/daily-sales-chart-data\/', views.get_daily_sales_chart_data, name='daily_sales_chart_data'),\n]\n  <\/code><\/pre>\n<\/div>\n<p>Projenizin ana <code>urls.py<\/code> dosyas\u0131na <code>myapp.urls<\/code>&#8216;i dahil etmeyi unutmay\u0131n: <code>path('myapp\/', include('myapp.urls')),<\/code><\/p>\n<p><strong>Ad\u0131m 4: Admin \u015eablonunu Geni\u015fletme ve Grafi\u011fi Entegre Etme<\/strong><\/p>\n<p><code>templates\/admin\/base_site.html<\/code> dosyas\u0131n\u0131 olu\u015fturun veya g\u00fcncelleyin. Bu \u015fablon, Admin paneli ana sayfas\u0131nda grafi\u011fi g\u00f6sterecek HTML ve JavaScript kodunu i\u00e7erecek.<\/p>\n<div class=\"code-container\">\n<pre><code>\n&lt;!-- templates\/admin\/base_site.html --&gt;\n{% extends \"admin\/base.html\" %}\n{% load static %}\n\n{% block extrahead %}\n  &lt;!-- Chart.js CDN --&gt;\n  &lt;script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"&gt;&lt;\/script&gt;\n{% endblock %}\n\n{% block content %}\n  {{ block.super }}\n\n  &lt;div style=\"margin: 20px; padding: 20px; background-color: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);\"&gt;\n    &lt;h3&gt;Son 7 G\u00fcnl\u00fck Toplam Sat\u0131\u015f Geliri&lt;\/h3&gt;\n    &lt;div class=\"chart-container\" style=\"position: relative; height:40vh; width:90vw; max-width: 900px;\"&gt;\n      &lt;canvas id=\"salesRevenueChart\"&gt;&lt;\/canvas&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n\n  &lt;script&gt;\n    document.addEventListener('DOMContentLoaded', function() {\n      const ctx = document.getElementById('salesRevenueChart').getContext('2d');\n      let salesRevenueChart;\n\n      function fetchAndRenderChart() {\n        fetch('\/myapp\/api\/daily-sales-chart-data\/')\n          .then(response => {\n            if (!response.ok) {\n              throw new Error(<code>HTTP Hata! Durum: ${response.status}<\/code>);\n            }\n            return response.json();\n          })\n          .then(data => {\n            const labels = data.sales.map(item => item.date);\n            const revenues = data.sales.map(item => item.total_sales);\n\n            if (salesRevenueChart) {\n              salesRevenueChart.data.labels = labels;\n              salesRevenueChart.data.datasets[0].data = revenues;\n              salesRevenueChart.update();\n            } else {\n              salesRevenueChart = new Chart(ctx, {\n                type: 'line',\n                data: {\n                  labels: labels,\n                  datasets: [{\n                    label: 'Toplam Gelir (\u20ba)',\n                    data: revenues,\n                    backgroundColor: 'rgba(54, 162, 235, 0.5)',\n                    borderColor: 'rgba(54, 162, 235, 1)',\n                    borderWidth: 2,\n                    fill: true,\n                    tension: 0.3 \/\/ \u00c7izgi yumu\u015fakl\u0131\u011f\u0131n\u0131 ayarlar\n                  }]\n                },\n                options: {\n                  responsive: true,\n                  maintainAspectRatio: false,\n                  plugins: {\n                      legend: {\n                          display: true,\n                          position: 'top',\n                      },\n                      title: {\n                          display: false,\n                          text: 'G\u00fcnl\u00fck Sat\u0131\u015f Gelirleri'\n                      }\n                  },\n                  scales: {\n                    y: {\n                      beginAtZero: true,\n                      title: {\n                        display: true,\n                        text: 'Gelir (\u20ba)'\n                      }\n                    },\n                    x: {\n                        title: {\n                            display: true,\n                            text: 'Tarih'\n                        }\n                    }\n                  }\n                }\n              });\n            }\n          })\n          .catch(error => console.error('Sat\u0131\u015f geliri verileri \u00e7ekilirken hata olu\u015ftu:', error));\n      }\n\n      \/\/ \u0130lk y\u00fcklemede ve sonra her 60 saniyede bir g\u00fcncelleyelim\n      fetchAndRenderChart();\n      setInterval(fetchAndRenderChart, 60000); \/\/ Her 1 dakikada bir g\u00fcncelle\n    });\n  &lt;\/script&gt;\n{% endblock %}\n  <\/code><\/pre>\n<\/div>\n<p><strong>Ad\u0131m 5: Veri Giri\u015fi ve Test<\/strong><\/p>\n<p>Admin paneline giri\u015f yap\u0131n ve <code>Sipari\u015fler<\/code> modelinize birka\u00e7 sipari\u015f verisi ekleyin. Farkl\u0131 tarihlerde ve farkl\u0131 fiyatlarla sipari\u015fler girerek grafi\u011fin nas\u0131l tepki verdi\u011fini g\u00f6zlemleyin. \u00d6rne\u011fin, bug\u00fcne ait birka\u00e7 sipari\u015f ekledikten sonra Admin ana sayfas\u0131na geri d\u00f6nd\u00fc\u011f\u00fcn\u00fczde, 60 saniye i\u00e7inde grafi\u011fin g\u00fcncellendi\u011fini ve bug\u00fcn\u00fcn sat\u0131\u015f verilerini yans\u0131tt\u0131\u011f\u0131n\u0131 g\u00f6receksiniz. Bu, canl\u0131 grafik \u00e7\u00f6z\u00fcm\u00fcm\u00fcz\u00fcn ba\u015far\u0131yla \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131n bir g\u00f6stergesidir.<\/p>\n<p>Bu ger\u00e7ek d\u00fcnya senaryosu, Django Admin&#8217;e canl\u0131 grafikler eklemenin pratik ad\u0131mlar\u0131n\u0131 ve faydalar\u0131n\u0131 net bir \u015fekilde ortaya koymaktad\u0131r. Bu yakla\u015f\u0131m, sadece sat\u0131\u015f verileriyle s\u0131n\u0131rl\u0131 kalmay\u0131p, kullan\u0131c\u0131 kay\u0131tlar\u0131, stok hareketleri, ziyaret\u00e7i istatistikleri veya herhangi bir zaman serisi verisi i\u00e7in de kolayca uyarlanabilir. Bu esneklik, projenize de\u011fer katarken, ek ba\u011f\u0131ml\u0131l\u0131klar\u0131n getirdi\u011fi karma\u015f\u0131kl\u0131ktan ka\u00e7\u0131nman\u0131z\u0131 sa\u011flar.<\/p>\n<h3>Performans ve G\u00fcvenlik \u0130pu\u00e7lar\u0131<\/h3>\n<p>Django Admin paneline canl\u0131 grafikler eklerken performans ve g\u00fcvenlik konular\u0131n\u0131 g\u00f6z ard\u0131 etmemek hayati \u00f6nem ta\u015f\u0131r. Harici paket kullanm\u0131yor olmam\u0131z, bu sorumluluklar\u0131n tamamen bize ait oldu\u011fu anlam\u0131na gelir. Do\u011fru optimizasyon ve g\u00fcvenlik \u00f6nlemleri, uygulaman\u0131z\u0131n sorunsuz ve g\u00fcvenli \u00e7al\u0131\u015fmas\u0131n\u0131 sa\u011flar.<\/p>\n<h4>Performans \u0130pu\u00e7lar\u0131<\/h4>\n<ol>\n<li><strong>Veri \u00c7ekme S\u0131kl\u0131\u011f\u0131n\u0131 Optimize Edin:<\/strong> <code>setInterval()<\/code> ile belirledi\u011finiz g\u00fcncelleme aral\u0131\u011f\u0131 kritik bir fakt\u00f6rd\u00fcr. \u00c7ok s\u0131k (\u00f6rne\u011fin, her 1-2 saniyede bir) veri \u00e7ekmek, sunucunuzda gereksiz y\u00fck olu\u015fturabilir ve veritaban\u0131 performans\u0131n\u0131 olumsuz etkileyebilir. Verilerinizin ne kadar &#8220;canl\u0131&#8221; olmas\u0131 gerekti\u011fine karar verin. \u00c7o\u011fu i\u015f zekas\u0131 paneli i\u00e7in 30 saniye ile 5 dakika aras\u0131 bir g\u00fcncelleme aral\u0131\u011f\u0131 genellikle yeterlidir.<\/li>\n<li><strong>Sadece \u0130htiyac\u0131n\u0131z Olan Veriyi \u00c7ekin:<\/strong> API u\u00e7 noktan\u0131zdan sadece grafi\u011fi \u00e7izmek i\u00e7in gerekli olan minimum veriyi d\u00f6nd\u00fcr\u00fcn. \u00d6rne\u011fin, 1000 farkl\u0131 \u00fcr\u00fcn\u00fcn detaylar\u0131n\u0131 de\u011fil, sadece g\u00fcnl\u00fck toplam sat\u0131\u015flar\u0131 veya belirli bir metrik i\u00e7in \u00f6zetlenmi\u015f verileri g\u00f6nderin. B\u00fcy\u00fck veri setlerini taray\u0131c\u0131ya g\u00f6ndermek, a\u011f trafi\u011fini art\u0131r\u0131r ve \u00f6n y\u00fcz performans\u0131n\u0131 d\u00fc\u015f\u00fcr\u00fcr. Django sorgular\u0131n\u0131z\u0131 <code>.values()<\/code>, <code>.annotate()<\/code> ve <code>.only()<\/code> gibi metotlarla optimize ederek sadece gerekli alanlar\u0131 \u00e7ekin.<\/li>\n<li><strong>Sunucu Taraf\u0131 \u00d6nbellekleme (Caching):<\/strong> E\u011fer veri u\u00e7 noktan\u0131zdaki veriler \u00e7ok s\u0131k de\u011fi\u015fmiyorsa veya belirli bir s\u00fcre i\u00e7in ayn\u0131 kalabiliyorsa, Django&#8217;nun \u00f6nbellekleme (caching) mekanizmas\u0131n\u0131 kullanmay\u0131 d\u00fc\u015f\u00fcnebilirsiniz. \u00d6rne\u011fin, son 7 g\u00fcnl\u00fck sat\u0131\u015f verileri her saniye de\u011fi\u015fmez. Bu verileri belirli bir s\u00fcre (\u00f6rne\u011fin, 5 dakika) \u00f6nbellekte tutarak veritaban\u0131na yap\u0131lan sorgu say\u0131s\u0131n\u0131 azaltabilirsiniz.\n<div class=\"code-container\">\n<pre><code>\n# myapp\/views.py (\u00d6nbellekleme \u00f6rne\u011fi)\nfrom django.views.decorators.cache import cache_page\n\n@cache_page(60 * 5) # 5 dakika \u00f6nbellekle\ndef get_daily_sales_chart_data(request):\n    # ... mevcut veri \u00e7ekme mant\u0131\u011f\u0131 ...\n    return JsonResponse({'sales': sales_data})\n          <\/code><\/pre>\n<\/p><\/div>\n<\/li>\n<li><strong>Asenkron \u0130\u015flemler:<\/strong> \u00c7ok karma\u015f\u0131k veri toplama i\u015flemleri yap\u0131yorsan\u0131z, bu i\u015flemleri arka plan g\u00f6revlerine (\u00f6rne\u011fin, Celery kullanarak) devrederek API yan\u0131t s\u00fcresini k\u0131saltabilirsiniz. Ancak bu, &#8220;tek paket kurmadan&#8221; kural\u0131n\u0131 ihlal edebilir, bu y\u00fczden dikkatli olun. Daha basit \u00e7\u00f6z\u00fcmler i\u00e7in, veritaban\u0131 sorgular\u0131n\u0131z\u0131n indeksli oldu\u011fundan ve h\u0131zl\u0131 \u00e7al\u0131\u015ft\u0131\u011f\u0131ndan emin olun.<\/li>\n<li><strong>Taray\u0131c\u0131 Taraf\u0131 Optimizasyon:<\/strong> Chart.js gibi k\u00fct\u00fcphaneler genellikle iyi optimize edilmi\u015ftir. Ancak, \u00e7ok say\u0131da grafik veya \u00e7ok b\u00fcy\u00fck veri setleriyle \u00e7al\u0131\u015f\u0131yorsan\u0131z, taray\u0131c\u0131n\u0131n performans\u0131n\u0131 etkileyebilir. Grafikleri sadece g\u00f6r\u00fcn\u00fcr oldu\u011funda y\u00fcklemek veya daha az detayl\u0131 grafikler kullanmak gibi stratejiler d\u00fc\u015f\u00fcnebilirsiniz.<\/li>\n<\/ol>\n<h4>G\u00fcvenlik \u0130pu\u00e7lar\u0131<\/h4>\n<ol>\n<li><strong>API U\u00e7 Noktas\u0131 Eri\u015fimi:<\/strong> Olu\u015fturdu\u011funuz API u\u00e7 noktas\u0131n\u0131n (\u00f6rne\u011fin, <code>\/myapp\/api\/daily-sales-chart-data\/<\/code>) herkes taraf\u0131ndan eri\u015filebilir olmamas\u0131 \u00f6nemlidir. Bu veriler hassas olabilir. Django&#8217;nun kimlik do\u011frulama (authentication) ve yetkilendirme (authorization) sistemini kullanarak bu u\u00e7 noktay\u0131 koruyun. \u00d6rne\u011fin, sadece giri\u015f yapm\u0131\u015f ve belirli bir izne sahip kullan\u0131c\u0131lar\u0131n bu verilere eri\u015febilmesini sa\u011flay\u0131n.\n<div class=\"code-container\">\n<pre><code>\n# myapp\/views.py (Giri\u015f yapm\u0131\u015f kullan\u0131c\u0131 kontrol\u00fc)\nfrom django.contrib.auth.decorators import login_required\n\n@login_required\ndef get_daily_sales_chart_data(request):\n    # ... mevcut veri \u00e7ekme mant\u0131\u011f\u0131 ...\n    return JsonResponse({'sales': sales_data})\n          <\/code><\/pre>\n<\/p><\/div>\n<p>E\u011fer Admin paneli i\u00e7inde kullan\u0131l\u0131yorsa, <code>login_required<\/code> yeterli olabilir. Daha spesifik izinler i\u00e7in <code>user_passes_test<\/code> veya <code>PermissionRequiredMixin<\/code> kullanabilirsiniz.<\/p>\n<\/li>\n<li><strong>Veri Do\u011frulama ve Temizleme:<\/strong> API u\u00e7 noktan\u0131zdan d\u00f6nd\u00fcrd\u00fc\u011f\u00fcn\u00fcz verilerin temiz (sanitized) oldu\u011fundan emin olun. \u00d6zellikle kullan\u0131c\u0131 taraf\u0131ndan girilen verileri g\u00f6rselle\u015ftiriyorsan\u0131z, XSS (Cross-Site Scripting) sald\u0131r\u0131lar\u0131n\u0131 \u00f6nlemek i\u00e7in herhangi bir HTML veya JavaScript kodunun d\u00fcz metin olarak i\u015flendi\u011finden emin olun. Django&#8217;nun \u015fablon sistemi varsay\u0131lan olarak XSS korumas\u0131 sa\u011flar, ancak JSON yan\u0131tlar\u0131n\u0131zda da dikkatli olun.<\/li>\n<li><strong>CSRF Korumas\u0131:<\/strong> Django, POST istekleri i\u00e7in CSRF (Cross-Site Request Forgery) korumas\u0131 sa\u011flar. Bizim API u\u00e7 noktam\u0131z GET iste\u011fi oldu\u011fu i\u00e7in do\u011frudan bir CSRF riski ta\u015f\u0131maz. Ancak, e\u011fer gelecekte bu u\u00e7 noktadan veri g\u00f6nderme (POST, PUT, DELETE) i\u015flemleri de yapacaksan\u0131z, JavaScript taraf\u0131nda CSRF token&#8217;\u0131n\u0131 y\u00f6netmeniz gerekecektir.\n<div class=\"code-container\">\n<pre><code>\n\/\/ JavaScript (POST iste\u011fi i\u00e7in CSRF token kullan\u0131m\u0131)\nfunction getCookie(name) {\n    let cookieValue = null;\n    if (document.cookie && document.cookie !== '') {\n        const cookies = document.cookie.split(';');\n        for (let i = 0; i &lt; cookies.length; i++) {\n            const cookie = cookies[i].trim();\n            \/\/ Does this cookie string begin with the name we want?\n            if (cookie.substring(0, name.length + 1) === (name + '=')) {\n                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n                break;\n            }\n        }\n    }\n    return cookieValue;\n}\nconst csrftoken = getCookie('csrftoken');\n\nfetch('\/some-post-api\/', {\n    method: 'POST',\n    headers: {\n        'Content-Type': 'application\/json',\n        'X-CSRFToken': csrftoken\n    },\n    body: JSON.stringify({ key: 'value' })\n})\n          <\/code><\/pre>\n<\/p><\/div>\n<\/li>\n<li><strong>HTTPS Kullan\u0131m\u0131:<\/strong> T\u00fcm web trafi\u011finizin (hem Admin paneli hem de API istekleri) HTTPS \u00fczerinden ger\u00e7ekle\u015fti\u011finden emin olun. Bu, verilerin a\u011f \u00fczerinde \u015fifrelenmesini ve man-in-the-middle sald\u0131r\u0131lar\u0131ndan korunmas\u0131n\u0131 sa\u011flar.<\/li>\n<\/ol>\n<p>Bu performans ve g\u00fcvenlik ipu\u00e7lar\u0131n\u0131 uygulayarak, Django Admin panelinize ekledi\u011finiz canl\u0131 grafiklerin hem h\u0131zl\u0131 ve verimli \u00e7al\u0131\u015fmas\u0131n\u0131 hem de hassas verilerinizin g\u00fcvende kalmas\u0131n\u0131 sa\u011flayabilirsiniz. Unutmay\u0131n, g\u00fcvenlik ve performans, ba\u015far\u0131l\u0131 bir uygulaman\u0131n temel ta\u015flar\u0131d\u0131r.<\/p>\n<h3>Sonu\u00e7 ve S\u0131k\u00e7a Sorulan Sorular<\/h3>\n<p>Bu makale boyunca, Django Admin paneline tek bir harici Python paketi kurmadan, canl\u0131 ve dinamik grafikler eklemenin kapsaml\u0131 bir yol haritas\u0131n\u0131 sunduk. Django&#8217;nun kendi g\u00fc\u00e7l\u00fc arka plan yeteneklerini (modeller, g\u00f6r\u00fcn\u00fcmler, URL y\u00f6nlendirme) ve modern \u00f6n y\u00fcz teknolojilerini (HTML, JavaScript, Chart.js, AJAX) birle\u015ftirerek, statik veri g\u00f6r\u00fcnt\u00fcleme s\u0131n\u0131rlar\u0131n\u0131 nas\u0131l a\u015ft\u0131\u011f\u0131m\u0131z\u0131 ad\u0131m ad\u0131m inceledik. Bu yakla\u015f\u0131m, sadece ba\u011f\u0131ml\u0131l\u0131klar\u0131 azaltmakla kalm\u0131yor, ayn\u0131 zamanda projenizin \u00fczerinde tam kontrol sahibi olman\u0131z\u0131 ve \u00f6zelle\u015ftirme esnekli\u011finizi art\u0131rman\u0131z\u0131 sa\u011fl\u0131yor.<\/p>\n<p>\u00d6\u011frendi\u011fimiz temel ad\u0131mlar \u015funlard\u0131:<\/p>\n<ol>\n<li><strong>Veri Kayna\u011f\u0131n\u0131 Haz\u0131rlama:<\/strong> Django modellerinden \u00e7ekilen verileri, <code>JsonResponse<\/code> kullanarak JSON format\u0131nda sunan basit bir API u\u00e7 noktas\u0131 olu\u015fturduk.<\/li>\n<li><strong>Admin \u015eablonlar\u0131n\u0131 Geni\u015fletme:<\/strong> <code>templates\/admin\/base_site.html<\/code> dosyas\u0131n\u0131 ge\u00e7ersiz k\u0131larak, grafi\u011fimiz i\u00e7in bir HTML <code>&lt;canvas&gt;<\/code> elementi ve Chart.js k\u00fct\u00fcphanesini dahil ettik.<\/li>\n<li><strong>Grafi\u011fi \u00c7izme ve G\u00fcncelleme:<\/strong> JavaScript ile Chart.js kullanarak grafi\u011fi \u00e7izdik ve <code>fetch()<\/code> API&#8217;si ile AJAX istekleri g\u00f6ndererek verileri dinamik olarak \u00e7ektik. <code>setInterval()<\/code> ile grafi\u011fi d\u00fczenli aral\u0131klarla g\u00fcncelleyerek canl\u0131l\u0131k kazand\u0131rd\u0131k.<\/li>\n<li><strong>Performans ve G\u00fcvenlik:<\/strong> Veri \u00e7ekme s\u0131kl\u0131\u011f\u0131n\u0131 optimize etme, \u00f6nbellekleme kullanma ve API u\u00e7 noktalar\u0131n\u0131 yetkilendirme gibi \u00f6nemli ipu\u00e7lar\u0131n\u0131 ele ald\u0131k.<\/li>\n<\/ol>\n<p>Bu y\u00f6ntem, Django Admin&#8217;i sadece bir veri y\u00f6netim arac\u0131 olmaktan \u00e7\u0131kar\u0131p, anl\u0131k i\u015f zekas\u0131 paneline d\u00f6n\u00fc\u015ft\u00fcrmek i\u00e7in g\u00fc\u00e7l\u00fc ve esnek bir temel sunar. Art\u0131k y\u00f6neticileriniz veya i\u015f analistleriniz, kritik metrikleri do\u011frudan Admin panelinden takip ederek daha h\u0131zl\u0131 ve bilin\u00e7li kararlar alabilirler. Bu, \u00f6zellikle k\u00fc\u00e7\u00fck ve orta \u00f6l\u00e7ekli projeler i\u00e7in, pahal\u0131 BI ara\u00e7lar\u0131na yat\u0131r\u0131m yapmadan b\u00fcy\u00fck de\u011fer yaratman\u0131n maliyet etkin bir yoludur. Bu beceriler, genel web geli\u015ftirme yeteneklerinizi de \u00f6nemli \u00f6l\u00e7\u00fcde geli\u015ftirecektir.<\/p>\n<h4>S\u0131k\u00e7a Sorulan Sorular<\/h4>\n<p><strong>1. Bu y\u00f6ntem sadece Chart.js ile mi \u00e7al\u0131\u015f\u0131r? Ba\u015fka grafik k\u00fct\u00fcphaneleri kullanabilir miyim?<\/strong><\/p>\n<p>Hay\u0131r, kesinlikle sadece Chart.js ile s\u0131n\u0131rl\u0131 de\u011filsiniz. Bu makaledeki temel prensipler (Django API u\u00e7 noktas\u0131, Admin \u015fablonu override etme, AJAX ile veri \u00e7ekme, JavaScript ile g\u00f6rselle\u015ftirme) herhangi bir client-side grafik k\u00fct\u00fcphanesiyle (\u00f6rne\u011fin, D3.js, ApexCharts, Google Charts) uygulanabilir. \u00d6nemli olan, k\u00fct\u00fcphanenin CDN \u00fczerinden kolayca y\u00fcklenebilir olmas\u0131 ve Python ortam\u0131na bir ba\u011f\u0131ml\u0131l\u0131k eklememesi.<\/p>\n<p><strong>2. Admin panelindeki farkl\u0131 sayfalara farkl\u0131 grafikler ekleyebilir miyim?<\/strong><\/p>\n<p>Evet, kesinlikle. <code>admin\/base_site.html<\/code> t\u00fcm Admin panelini etkilerken, belirli bir modelin listeleme sayfas\u0131 i\u00e7in <code>admin\/change_list.html<\/code> veya detay sayfas\u0131 i\u00e7in <code>admin\/change_form.html<\/code> gibi \u015fablonlar\u0131 override edebilirsiniz. \u00d6rne\u011fin, bir \u00fcr\u00fcn modelinin listeleme sayfas\u0131nda stok durumunu g\u00f6steren bir \u00e7ubuk grafik eklemek i\u00e7in <code>admin\/myapp\/urun\/change_list.html<\/code> dosyas\u0131n\u0131 olu\u015fturup \u00f6zelle\u015ftirebilirsiniz.<\/p>\n<p><strong>3. Verilerim \u00e7ok b\u00fcy\u00fckse ve binlerce veri noktas\u0131 i\u00e7eriyorsa ne yapmal\u0131y\u0131m?<\/strong><\/p>\n<p>B\u00fcy\u00fck veri setleri i\u00e7in do\u011frudan t\u00fcm veri noktalar\u0131n\u0131 taray\u0131c\u0131ya g\u00f6ndermek performans sorunlar\u0131na yol a\u00e7abilir. Bu durumda, sunucu taraf\u0131nda verileri \u00f6zetleme (aggregation) veya \u00f6rnekleme (sampling) tekniklerini kullanman\u0131z \u00f6nerilir. \u00d6rne\u011fin, g\u00fcnl\u00fck yerine haftal\u0131k veya ayl\u0131k toplamlar\u0131 d\u00f6nd\u00fcrebilir, ya da \u00e7ok b\u00fcy\u00fck bir zaman aral\u0131\u011f\u0131 i\u00e7in verileri daha az detayl\u0131 bir \u015fekilde g\u00f6sterebilirsiniz. Ayr\u0131ca, performans ipu\u00e7lar\u0131ndaki \u00f6nbellekleme stratejilerini uygulamak da faydal\u0131 olacakt\u0131r.<\/p>\n<p><strong>4. Django Admin&#8217;e grafik eklemek i\u00e7in neden \u00fc\u00e7\u00fcnc\u00fc taraf Python paketleri yerine bu y\u00f6ntemi tercih etmeliyim?<\/strong><\/p>\n<p>Bu y\u00f6ntemi tercih etmenin ana nedenleri aras\u0131nda daha az ba\u011f\u0131ml\u0131l\u0131k, daha basit da\u011f\u0131t\u0131m, projeniz \u00fczerinde tam kontrol ve daha iyi g\u00fcvenlik say\u0131labilir. Her yeni Python paketi, projenize ek bir karma\u015f\u0131kl\u0131k katman\u0131 ekler. Mevcut ara\u00e7larla \u00e7\u00f6z\u00fclebilecek bir problemi, gereksiz ba\u011f\u0131ml\u0131l\u0131klar eklemeden \u00e7\u00f6zmek, uzun vadede daha s\u00fcrd\u00fcr\u00fclebilir bir yakla\u015f\u0131m olabilir. Ayr\u0131ca, bu y\u00f6ntem \u00f6n y\u00fcz geli\u015ftirme becerilerinizi de geli\u015ftirmenize yard\u0131mc\u0131 olur.<\/p>\n<p><strong>5. Grafiklerin g\u00f6r\u00fcn\u00fcm\u00fcn\u00fc (renkler, fontlar vb.) nas\u0131l \u00f6zelle\u015ftirebilirim?<\/strong><\/p>\n<p>Chart.js, grafiklerin g\u00f6r\u00fcn\u00fcm\u00fcn\u00fc \u00f6zelle\u015ftirmek i\u00e7in zengin se\u00e7enekler sunar. <code>options<\/code> nesnesi i\u00e7inde renkleri, fontlar\u0131, eksen ayarlar\u0131n\u0131, efsaneleri (legends) ve daha bir\u00e7ok g\u00f6rsel \u00f6\u011feyi kontrol edebilirsiniz. Ayr\u0131ca, kendi CSS stil dosyalar\u0131n\u0131z\u0131 Admin \u015fablonuna dahil ederek veya do\u011frudan HTML elementlerine stil vererek genel g\u00f6r\u00fcn\u00fcm\u00fc Django Admin temas\u0131na uygun hale getirebilirsiniz. Bu makalede inline style kullanmaktan ka\u00e7\u0131n\u0131lsa da, pratik uygulamalarda CSS dosyalar\u0131 ile daha kapsaml\u0131 tema entegrasyonu yapmak m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<p>#Django #WebGeli\u015ftirme #Canl\u0131Grafikler #AdminPanel #JavaScript<\/p>\n<div class=\"github-example-link\"><strong>\u00d6rnek kod:<\/strong> <a href=\"https:\/\/github.com\/fatihsoysalcom\/django-admin-live-chart-no-packages\" target=\"_blank\" rel=\"noopener noreferrer\">github.com\/fatihsoysalcom\/django-admin-live-chart-no-packages<\/a><\/div>\n","protected":false},"excerpt":{"rendered":"Django y\u00f6netim panelinizdeki statik veriler sizi yoruyor ve anl\u0131k kararlar alman\u0131z\u0131 engelliyor mu?","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-42137","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 Admin&#039;e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131<\/title>\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-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Django Admin&#039;e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim?\" \/>\n<meta property=\"og:description\" content=\"Django y\u00f6netim panelinizdeki statik veriler sizi yoruyor ve anl\u0131k kararlar alman\u0131z\u0131 engelliyor mu?\" \/>\n<meta property=\"og:url\" content=\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/\" \/>\n<meta property=\"og:site_name\" content=\"Kodlar\u0131n Gizemli D\u00fcnyas\u0131\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-28T06:11:34+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-28T06:12:09+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=\"32 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/\"},\"author\":{\"name\":\"Fatih Soysal\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"headline\":\"Django Admin&#8217;e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim?\",\"datePublished\":\"2026-05-28T06:11:34+00:00\",\"dateModified\":\"2026-05-28T06:12:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/\"},\"wordCount\":4759,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/#respond\"]}],\"copyrightYear\":\"2026\",\"copyrightHolder\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/\",\"url\":\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/\",\"name\":\"Django Admin'e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131\",\"isPartOf\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/#website\"},\"datePublished\":\"2026-05-28T06:11:34+00:00\",\"dateModified\":\"2026-05-28T06:12:09+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Anasayfa\",\"item\":\"https:\/\/fatihsoysal.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Django Admin&#8217;e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim?\"}]},{\"@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 Admin'e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","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-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/","og_locale":"tr_TR","og_type":"article","og_title":"Django Admin'e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim?","og_description":"Django y\u00f6netim panelinizdeki statik veriler sizi yoruyor ve anl\u0131k kararlar alman\u0131z\u0131 engelliyor mu?","og_url":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/","og_site_name":"Kodlar\u0131n Gizemli D\u00fcnyas\u0131","article_published_time":"2026-05-28T06:11:34+00:00","article_modified_time":"2026-05-28T06:12:09+00:00","author":"Fatih Soysal","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"Fatih Soysal","Tahmini okuma s\u00fcresi":"32 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/#article","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/"},"author":{"name":"Fatih Soysal","@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"headline":"Django Admin&#8217;e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim?","datePublished":"2026-05-28T06:11:34+00:00","dateModified":"2026-05-28T06:12:09+00:00","mainEntityOfPage":{"@id":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/"},"wordCount":4759,"commentCount":0,"publisher":{"@id":"https:\/\/fatihsoysal.com\/blog\/#\/schema\/person\/002a254750921dcfd568a99e48240dd1"},"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/#respond"]}],"copyrightYear":"2026","copyrightHolder":{"@id":"https:\/\/fatihsoysal.com\/blog\/#organization"}},{"@type":"WebPage","@id":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/","url":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/","name":"Django Admin'e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim? - Kodlar\u0131n Gizemli D\u00fcnyas\u0131","isPartOf":{"@id":"https:\/\/fatihsoysal.com\/blog\/#website"},"datePublished":"2026-05-28T06:11:34+00:00","dateModified":"2026-05-28T06:12:09+00:00","breadcrumb":{"@id":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/fatihsoysal.com\/blog\/django-admine-tek-bir-paket-bile-kurmadan-canli-grafikler-nasil-ekledim\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Anasayfa","item":"https:\/\/fatihsoysal.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Django Admin&#8217;e Tek Bir Paket Bile Kurmadan Canl\u0131 Grafikler Nas\u0131l Ekledim?"}]},{"@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\/42137","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=42137"}],"version-history":[{"count":1,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/42137\/revisions"}],"predecessor-version":[{"id":42138,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/posts\/42137\/revisions\/42138"}],"wp:attachment":[{"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/media?parent=42137"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/categories?post=42137"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fatihsoysal.com\/blog\/wp-json\/wp\/v2\/tags?post=42137"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}