biotech Django & Python

Django Projesini PWA'ya Dönüştürme: 2026 Tam Rehber

AK
Ali Kasımoğlu
13 Şub 2021 schedule 8 dk okuma
Django Projesini {p}PWA'ya Dönüştürme{/p}: 2026 Tam Rehber
analytics

Insight Density

groups Hedef Kitle: Deneyimli
65 Score

Teknik karmaşıklık ve içerik yoğunluğuna göre hesaplandı.

Son güncelleme: Nisan 2026 · AnomixLabs Teknik Ekibi

PWA, native uygulama geliştirmek yerine web'in evrensel erişilebilirliğinden ödün vermeden uygulama deneyimi sunmanın en pragmatik yolu — özellikle Django arka planı olanlar için.

PWA Nedir?

Progressive Web App (PWA), modern web teknolojileriyle geliştirilen ve native uygulama benzeri deneyim sunan web uygulamalarıdır. Üç temel bileşen: Web App Manifest (kurulum bilgileri), Service Worker (arka plan işleme ve offline cache), HTTPS (güvenlik zorunluluğu).

PWA avantajları: App Store bağımsızlığı, %30 komisyon yok, anında güncelleme, tek kod tabanı tüm platformlar, arama motorlarında indekslenebilirlik.

iOS 17.4 PWA Değişiklikleri: Önemli Güncelleme

Apple, iOS 17.4 ile Avrupa'da home screen PWA desteğini kaldırdığını duyurdu (Şubat 2024), ardından DMA (Digital Markets Act) baskısıyla bu karardan geri döndü (Mart 2024). Gelinen nokta:

  • iOS'ta PWA home screen kurulumu tüm bölgelerde hâlâ destekleniyor
  • iOS 17.4+ service worker desteği iyileştirildi
  • Push notification: iOS 16.4+'dan itibaren Web Push API desteği mevcut — ama kullanıcı izni gerektiriyor ve bazı kısıtlamalar var
  • Tam ekran modu (standalone) iOS'ta çalışıyor ama bazı native API'ler hâlâ eksik (Face ID, NFC vb.)

Django URL Yapılandırması

PWA'nın üç dosyası (manifest.json, sw.js, offline/) Django'nun URL yönlendiricisinden geçmelidir — statik dosya olarak değil, çünkü tarayıcı bu dosyaları root scope'dan bekler:

from django.urls import path
from django.views.generic import TemplateView

urlpatterns = [
    # manifest.json — tarayıcı bu URL'yi arar
    path('manifest.json', TemplateView.as_view(
        template_name='manifest.json',
        content_type='application/manifest+json'
    ), name='manifest'),

    # Service Worker — root scope'da olmalı (/sw.js)
    path('sw.js', TemplateView.as_view(
        template_name='sw.js',
        content_type='application/javascript'
    ), name='service-worker'),

    # Offline sayfası — cache'te tutulur
    path('offline/', TemplateView.as_view(
        template_name='offline.html'
    ), name='offline'),
]

Bu URL'leri i18n_patterns() dışında, dil öneki almadan tanımlayın. Aksi takdirde tarayıcı /sw.js yerine /tr/sw.js arar ve service worker kaydı başarısız olur.

Web App Manifest

Manifest dosyası, tarayıcıya uygulamanızın nasıl kurulacağını söyler:

{
  "name": "AnomixLabs App",
  "short_name": "Anomix",
  "description": "Django ile güçlendirilmiş web uygulaması",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#1a1a2e",
  "orientation": "portrait-primary",
  "icons": [
    {
      "src": "/static/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any maskable"
    },
    {
      "src": "/static/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

Manifest Alan Referansı

En sık kullanılan manifest.json alanlarının açıklaması:

PWA standalone display modu — tarayıcı arayüzü gizli PWA minimal-ui display modu — minimum tarayıcı arayüzü PWA theme_color — tarayıcı toolbar ve Android bildirim çubuğu rengi PWA uygulama kısayolları — uzun basışta kısayol menüsü

Alan Açıklama
name Uygulamanın tam adı. Splash screen ve yükleme ekranında görünür. Belirtilmezse short_name kullanılır.
short_name Ana ekranda ikon altında görünen kısa ad. 12 karakteri geçmemesi önerilir.
start_url Uygulama ikonuna tıklandığında açılacak URL. "/" ana sayfayı işaret eder.
display standalone: adres çubuğu gizli — en yaygın kullanım. fullscreen: tam ekran. minimal-ui: küçük geri butonu. browser: normal tarayıcı görünümü.
background_color Splash screen (açılış) arka plan rengi. CSS yüklenmeden önce görünür.
theme_color Android Chrome'da tarayıcı araç çubuğu rengi ve görev çubuğu rengi. HTML'de <meta name="theme-color"> ile eşleşmeli.
icons Farklı boyutlar için ikon listesi. Chrome minimum 192×192 ve 512×512 gerektirir. purpose: "maskable" Android'de yuvarlak ikon için gerekli. Tüm boyutlar: 72, 96, 128, 144, 152, 192, 384, 512 piksel.
shortcuts İkon uzun basıldığında (long press) açılan hızlı erişim menüsü. Her kısayol için name, url ve icons tanımlanır.
orientation Desteklenen ekran yönü. "any" hem dikey hem yatay çalışır.
prefer_related_applications true yapılırsa tarayıcı PWA yerine Play Store/App Store uygulamasını önerir. Genellikle false bırakılır.
lang / dir İçeriğin dili ("tr-TR", "en-US") ve yazı yönü ("ltr" veya "rtl").

Django'da bu dosyayı staticfiles ile servledin ve HTML head'e bağlantı ekleyin:

<!-- base.html <head> bölümüne ekle -->
<link rel="manifest" href="{% url 'manifest' %}">
<meta name="theme-color" content="#1a1a2e">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="AnomixLabs">
<link rel="apple-touch-icon" href="{% static 'icons/icon-192.png' %}">

Service Worker: Temel Yapı

Service Worker, arka planda çalışan JavaScript dosyasıdır. Ana thread'dan bağımsız çalışır ve network isteklerini intercept eder:

// sw.js — Service Worker
const CACHE_NAME = 'anomix-v1';
const STATIC_ASSETS = [
  '/',
  '/static/css/main.css',
  '/static/js/app.js',
  '/offline/',
];

// Install: statik dosyaları cache'e al
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => cache.addAll(STATIC_ASSETS))
  );
  self.skipWaiting();
});

// Activate: eski cache'leri temizle
self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then(keys =>
      Promise.all(keys.filter(k => k !== CACHE_NAME).map(k => caches.delete(k)))
    )
  );
  self.clients.claim();
});

// Fetch: önce cache, sonra network (Cache-First strateji)
self.addEventListener('fetch', (event) => {
  if (event.request.method !== 'GET') return;
  event.respondWith(
    caches.match(event.request).then(cached => {
      if (cached) return cached;
      return fetch(event.request).catch(() => caches.match('/offline/'));
    })
  );
});

Django'da Service Worker'ı kaydetmek:

// main.js
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js', { scope: '/' })
      .then(reg => console.log('SW registered:', reg.scope))
      .catch(err => console.log('SW failed:', err));
  });
}

Önemli: Service Worker dosyasının Django URL'lerinden önce root path'de (/sw.js) servis edilmesi için URL yapılandırması gerekir:

# urls.py
from django.views.generic import TemplateView

urlpatterns = [
    path('sw.js', TemplateView.as_view(
        template_name='sw.js',
        content_type='application/javascript'
    ), name='service-worker'),
]

Workbox: Service Worker Yönetimini Kolaylaştıran Kütüphane

Google'ın Workbox kütüphanesi, service worker stratejilerini hazır API ile sunar:

// sw.js with Workbox
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies';
import { ExpirationPlugin } from 'workbox-expiration';

// Statik dosyaları precache et
precacheAndRoute(self.__WB_MANIFEST);

// Görseller: Cache-First (30 gün)
registerRoute(
  ({ request }) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [new ExpirationPlugin({ maxEntries: 60, maxAgeSeconds: 30 * 24 * 3600 })]
  })
);

// API istekleri: Network-First
registerRoute(
  ({ url }) => url.pathname.startsWith('/api/'),
  new NetworkFirst({ cacheName: 'api-cache', networkTimeoutSeconds: 3 })
);

// Sayfalar: Stale-While-Revalidate
registerRoute(
  ({ request }) => request.mode === 'navigate',
  new StaleWhileRevalidate({ cacheName: 'pages' })
);

Cache Stratejileri

  • Cache-First: Önce cache bak, yoksa ağdan al. Logo, font, statik CSS/JS için ideal.
  • Network-First: Önce ağdan al, başarısız olursa cache'e bak. API ve dinamik sayfa için.
  • Stale-While-Revalidate: Cache'ten hemen dön, arka planda güncelle. Haber sayfaları için ideal.
  • Cache-Only: Sadece cache — önceden yüklenen offline içerik için.
  • Network-Only: Cache kullanma — ödeme sayfaları gibi kritik işlemler için.

Web Push API: Django ile Push Bildirim

Web Push API, kullanıcının tarayıcıyı açmadan bile bildirim almasını sağlar. VAPID (Voluntary Application Server Identification) anahtarı gerektirir:

# pip install pywebpush
from pywebpush import webpush, WebPushException

def send_push_notification(subscription_info, message):
    try:
        webpush(
            subscription_info=subscription_info,
            data=json.dumps({'title': 'Anomix', 'body': message}),
            vapid_private_key=settings.VAPID_PRIVATE_KEY,
            vapid_claims={'sub': 'mailto:info@anomixlabs.com'}
        )
    except WebPushException as ex:
        logger.error('Push notification failed: %s', ex)

iOS kısıtlaması: iOS'ta push bildirim yalnızca home screen'e eklenmiş PWA'larda çalışır — tarayıcıda açık sayfada çalışmaz (iOS 16.4+). Android'de browser'dan da çalışır.

App Badging API

App Badging API, uygulama ikonuna okunmamış sayısı ekler — email veya mesajlaşma uygulamaları için:

// Bildirim sayısını badge'e yaz
if ('setAppBadge' in navigator) {
  navigator.setAppBadge(unreadCount);
}

// Badge'i temizle
if ('clearAppBadge' in navigator) {
  navigator.clearAppBadge();
}

Offline Deneyimi: /offline/ Sayfası

Kullanıcı offline olduğunda ve istenen sayfa cache'de yokken gösterilecek fallback sayfası:

PWA çevrimdışı sayfası — internet bağlantısı olmadığında görüntü

{% extends 'base.html' %}
{% block content %}
<div class="flex flex-col items-center justify-center min-h-[60vh] text-center px-4">
  <svg xmlns="http://www.w3.org/2000/svg" class="w-16 h-16 text-on-surface/20 mb-6"
       fill="none" viewBox="0 0 24 24" stroke="currentColor">
    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
          d="M3 15a4 4 0 004 4h10a5 5 0 002.45-9.34A7 7 0 106.33 15H3z" />
  </svg>
  <h1 class="text-2xl font-bold mb-2">İnternet bağlantısı yok</h1>
  <p class="text-on-surface/60 mb-8">Bu sayfa çevrimdışı mevcut değil.</p>
  <button onclick="window.location.reload()"
          class="px-6 py-3 bg-primary text-white rounded-xl font-medium
                 hover:opacity-90 transition-opacity">
    Tekrar dene
  </button>
</div>
{% endblock %}

Yükleme Bildirimi: beforeinstallprompt

Kullanıcılara PWA'yı ana ekrana eklemelerini teklif etmek için beforeinstallprompt olayını yakalayın. Tarayıcı bu olayı PWA kriterleri karşılandığında otomatik tetikler — sizin yapmanız gereken varsayılan davranışı engelleyip kendi UI'nızı göstermek:

PWA yükleme bildirimi arayüzü — beforeinstallprompt PWA uygulama yükleme butonu — Uygulamayı İndir tasarımı

<!-- base.html — </body> öncesine ekle -->
<div id="pwa-banner" class="hidden fixed bottom-5 left-5 z-50
     flex items-center gap-3 px-4 py-3 rounded-2xl
     bg-surface-container border border-on-surface/10 shadow-lg">
  <span class="text-sm text-on-surface">Uygulamayı ana ekrana ekle</span>
  <button id="pwa-install"
          class="px-4 py-1.5 bg-primary text-white text-sm rounded-xl font-medium">
    Yükle
  </button>
  <button id="pwa-dismiss" class="text-on-surface/40 text-lg leading-none">
    &times;
  </button>
</div>
let deferredPrompt;
const banner     = document.getElementById('pwa-banner');
const installBtn = document.getElementById('pwa-install');
const dismissBtn = document.getElementById('pwa-dismiss');

// Tarayıcı kurulum promtunu hazırladığında
window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();       // varsayılan banner'ı engelle
  deferredPrompt = e;
  banner.classList.remove('hidden');
});

// "Yükle" butonuna tıklandığında
installBtn?.addEventListener('click', async () => {
  banner.classList.add('hidden');
  deferredPrompt.prompt();
  const { outcome } = await deferredPrompt.userChoice;
  console.log('PWA install:', outcome);  // 'accepted' | 'dismissed'
  deferredPrompt = null;
});

// Kapat butonunu dinle
dismissBtn?.addEventListener('click', () => banner.classList.add('hidden'));

// Uygulama başarıyla yüklendiğinde
window.addEventListener('appinstalled', () => {
  banner.classList.add('hidden');
  console.log('PWA yüklendi');
});

// PWA mı yoksa normal browser'da mı açıldığını tespit et
const isPwa = navigator.standalone
  || window.matchMedia('(display-mode: standalone)').matches;
console.log('Başlatma modu:', isPwa ? 'PWA' : 'browser');

Tarayıcı desteği: beforeinstallprompt Chrome/Edge'de çalışır (Android ve masaüstü). Safari bu olayı tetiklemez — iOS kullanıcılarına "Paylaş → Ana Ekrana Ekle" yönlendirmesini manuel olarak gösterin (örneğin navigator.standalone === false kontrolüyle).

Lighthouse PWA Audit ile 100 Puan

Lighthouse PWA audit kriterleri:

  • HTTPS zorunlu
  • Service Worker kayıtlı ve aktif
  • Web App Manifest tüm zorunlu alanlarla dolu
  • 192x192 ve 512x512 maskable icon
  • Yönlendirme yoksa start_url cache'de mevcut
  • HTTP → HTTPS yönlendirmesi
  • theme-color meta tag

Özet

Django projesini PWA'ya dönüştürmek 3 ana adım: manifest.json yaz, service worker ekle (/sw.js), HTTPS'i doğrula. Workbox production'da service worker yönetimini kolaylaştırır. Push bildirim için pywebpush kütüphanesi ve VAPID anahtarı gerekli. iOS 17.4 sonrasında PWA desteği istikrarlı — ancak iOS'taki bazı native API kısıtlamaları devam ediyor.

Sıkça Sorulan Sorular

iOS'ta PWA push bildirimi çalışıyor mu? expand_more
iOS 16.4'ten itibaren evet, ama şartlı: kullanıcının önce PWA'yı home screen'e eklemesi gerekiyor. Tarayıcıda açık sayfada (Safari sekmesi) iOS push notification çalışmıyor — bu Android'den temel fark. Ayrıca kullanıcı izni gereklidir ve iOS'ta permission dialog otomatik tetiklenemiyor; kullanıcı eyleminden (tıklama) sonra requestPermission() çağrılmalı.
PWA App Store'a yüklenebilir mi? expand_more
Doğrudan hayır, ama dolaylı yollar mevcut. Google Play Store: TWA (Trusted Web Activity) ile Chrome tabanlı PWA'yı paketleyebilirsiniz. Apple App Store: WKWebView ile hybrid app olarak yüklenebilir ama bu native wrapper gerektirir. Microsoft Store: PWABuilder (pwabuilder.com) ile Package for Store seçeneği Windows için PWA yüklemeye izin veriyor. Her yol ek geliştirme gerektirir.
Service Worker'ı nasıl güncelleme stratejisi belirlemeliyim? expand_more
Yeni service worker yüklenince eski sayfalar hâlâ eski SW kullanır — güncelleme için tarayıcı yeniden başlatma veya tüm sekmelerin kapatılması gerekir. skipWaiting() + clients.claim() kombinasyonu anında güncellemeye zorlar ama eski cache ile yeni SW arasında uyumsuzluk riski yaratır. Önerilen: postMessage ile sayfaya 'güncelleme mevcut' mesajı gönder, kullanıcıya 'sayfayı yenilemek ister misiniz?' sor.
Offline-first mi, cache-first mi tercih edilmeli? expand_more
Uygulama türüne göre. Offline-first: uygulama her zaman cache'ten çalışır, arka planda sync — haber uygulaması, not alma. Cache-first: önce cache, yoksa network — statik içerik ağırlıklı siteler. Network-first: önce güncel veri, offline fallback — e-ticaret, iletişim formları. Django projeleri için genellikle karma: statik asset için cache-first, API ve sayfalar için network-first veya stale-while-revalidate.
PWA'nın dezavantajları neler? expand_more
iOS uygulama mağazasında öne çıkma yok (discovery), bazı native API'lere erişim yok (Bluetooth, NFC, Face ID gibi), background sync ve geofencing sınırlı iOS'ta, bazı kurumsal MDM sistemleri PWA'ları kısıtlıyor. Ancak büyük çoğunluk için bu kısıtlamalar önemli değil — belge, katalog, iletişim, eğitim uygulamaları için PWA native uygulamaya pratik alternatif.
django-pwa paketi kullanmalı mıyım? expand_more
django-pwa, manifest ve service worker için minimal bir başlangıç noktası sunar. Ama 2024-2026 itibarıyla Workbox ile manuel kurulum daha esnektir ve daha iyi kontrol sağlar. django-pwa son güncellemesi 2022 — aktif olarak bakım görmüyor. Production için Workbox + manuel manifest tercih edin. Öğrenme amaçlı başlangıç için django-pwa makul bir başlangıç noktası.
Service Worker CSRF token sorununu nasıl çözerim? expand_more
Service Worker fetch event'i CSRF gerektiren POST isteklerini intercept ettiğinde token kaybı olabilir. Çözüm: SW'de POST isteklerini intercept etmeyin (sadece GET'ler için cache stratejisi uygulayın). Django'da API için DRF kullanıyorsanız JWT veya token auth SW ile daha uyumludur. Eğer intercept etmeniz gerekiyorsa isteği clone() ile kopyalayın ve orijinal header'ları koruyun.
Etiketler: #Django #PWA #Progressive Web App #Service Worker #Web Manifest #Push Notification #Workbox #iOS #Offline
share

Bu Makaleyi Paylaş

Bilgiyi ağınızla paylaşarak bize destek olun.

AK

Ali Kasımoğlu

Full-stack Geliştirici & AnomixLabs Kurucusu

Python ve Django ekosisteminde uzmanlaşmış bir yazılım geliştirici. Modern web mimarileri, yapay zeka entegrasyonları ve minimalist kullanıcı deneyimleri üzerine odaklanıyor. AnomixLabs çatısı altında, karmaşık problemleri yalın ve etkili dijital çözümlere dönüştürmeyi hedefliyor.

psychology
psychology

Makale Hakkında Soru Sorun

AnomixAI · Makale içeriğine dayalı yanıtlar

5 soru hakkı
Yalnızca makale içeriği hakkında 0/500
forward_to_inbox

Geleceği Çözümleyin.

Enterprise yapay zeka, yazılım mimarisi ve dijital dönüşüm üzerine aylık brifingi alan 5.000+ mühendis ve kurucuya katılın. Spam yok.