Django + Flutter Dosya Upload Sistemi (JWT Güvenlikli)

Bu rehber sonunda:

  • 📡 Django API (backend)

  • 📱 Flutter mobil uygulama (frontend)

  • 🔐 JWT Authentication

  • 📂 Dosya yükleme (image/file)

tam çalışan bir mimari kurmuş olacaksın.


GENEL MİMARİ

Flutter App
    ↓ (HTTP + JWT)
Django REST API
    ↓
Database + Media Files

⚙️ 1. DJANGO BACKEND KURULUMU

📦 Paketler

pip install djangorestframework
pip install djangorestframework-simplejwt
pip install pillow

🔧 settings.py

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

🧱 Model

from django.db import models

class Upload(models.Model):
    title = models.CharField(max_length=100)
    file = models.FileField(upload_to='uploads/')
    created_at = models.DateTimeField(auto_now_add=True)

🔌 Serializer

from rest_framework import serializers
from .models import Upload

class UploadSerializer(serializers.ModelSerializer):
    class Meta:
        model = Upload
        fields = '__all__'

🔐 JWT Login

from rest_framework_simplejwt.views import TokenObtainPairView

urlpatterns = [
    path('api/token/', TokenObtainPairView.as_view()),
]

📤 Upload API View

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

class FileUploadView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        file = request.FILES.get('file')
        title = request.data.get('title')

        upload = Upload.objects.create(
            title=title,
            file=file
        )

        return Response({
            "message": "Yüklendi",
            "file_url": upload.file.url
        })

🌐 urls.py

from django.urls import path
from .views import FileUploadView

urlpatterns = [
    path('upload/', FileUploadView.as_view()),
]

📱 2. FLUTTER TARAFI

📦 Paket

dependencies:
  http: ^0.13.6
  file_picker: ^6.1.1

📂 Dosya Seçme

import 'package:file_picker/file_picker.dart';

Future pickFile() async {
  final result = await FilePicker.platform.pickFiles();
  if (result != null) {
    return result.files.single.path;
  }
}

🔐 JWT Login (Token alma)

Future<String> login() async {
  final response = await http.post(
    Uri.parse("http://127.0.0.1:8000/api/token/"),
    body: {
      "username": "admin",
      "password": "1234"
    },
  );

  return jsonDecode(response.body)['access'];
}

📤 File Upload

import 'dart:io';
import 'package:http/http.dart' as http;

Future uploadFile(String path, String token) async {
  var request = http.MultipartRequest(
    'POST',
    Uri.parse("http://127.0.0.1:8000/upload/"),
  );

  request.headers['Authorization'] = 'Bearer $token';

  request.files.add(
    await http.MultipartFile.fromPath('file', path),
  );

  request.fields['title'] = "Flutter Upload";

  var response = await request.send();

  if (response.statusCode == 200) {
    print("Upload başarılı");
  } else {
    print("Hata");
  }
}

🧪 TEST AKIŞI

  1. Django server çalıştır:

python manage.py runserver
  1. Flutter’da:

  • Login ol → token al

  • Dosya seç

  • Upload yap


🖼️ BONUS – Flutter UI (Basit)

ElevatedButton(
  onPressed: () async {
    String path = await pickFile();
    String token = await login();
    await uploadFile(path, token);
  },
  child: Text("Dosya Yükle"),
)

🔥 PRO SEVİYE GELİŞTİRME

🚀 Ekleyebileceğimiz özellikler:

✅ 📊 Upload progress bar
✅ 🖼️ Resim önizleme
✅ 🗑️ Dosya silme API
✅ 📂 Çoklu dosya upload
✅ ☁️ AWS S3 entegrasyonu
✅ 🔒 Kullanıcıya özel dosyalar
✅ ⚡ Drag & Drop (Flutter Web)


🎯 GERÇEK PROJE FİKRİ

🎓 Okul Yönetim Sistemi

  • Öğrenci ödev yükler

  • Öğretmen dosyayı indirir

  • Admin kontrol eder






💻 1. FULL PROJE (Django + Flutter)

📁 PROJE YAPISI

project-root/
│
├── backend/ (Django API)
│   ├── config/
│   ├── apps/
│   │   └── uploads/
│   ├── media/
│   ├── requirements.txt
│
├── mobile/ (Flutter App)
│   ├── lib/
│   │   ├── screens/
│   │   ├── services/
│   │   ├── widgets/
│
└── README.md

🔧 BACKEND (DJANGO PRO)

📦 requirements.txt

Django
djangorestframework
djangorestframework-simplejwt
Pillow
django-cors-headers

⚙️ settings.py (PRO)

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

CORS_ALLOW_ALL_ORIGINS = True

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "rest_framework_simplejwt.authentication.JWTAuthentication",
    )
}

🧱 Model

class Upload(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=100)
    file = models.FileField(upload_to='uploads/')
    created_at = models.DateTimeField(auto_now_add=True)

🔌 Serializer

class UploadSerializer(serializers.ModelSerializer):
    class Meta:
        model = Upload
        fields = "__all__"

🔐 Login API

path('api/token/', TokenObtainPairView.as_view()),

📤 Upload API (PRO)

class UploadView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        file = request.FILES.get('file')

        upload = Upload.objects.create(
            user=request.user,
            title=request.data.get('title'),
            file=file
        )

        return Response({
            "id": upload.id,
            "file": upload.file.url
        })

📥 Dosya Listeleme API

class FileListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        files = Upload.objects.filter(user=request.user)
        serializer = UploadSerializer(files, many=True)
        return Response(serializer.data)


📱 FLUTTER PRO APP

📦 pubspec.yaml

dependencies:
  http: ^0.13.6
  file_picker: ^6.1.1
  provider: ^6.0.5

🧠 API Service

class ApiService {
  String baseUrl = "http://127.0.0.1:8000";

  Future<String> login(String user, String pass) async {
    final res = await http.post(
      Uri.parse("$baseUrl/api/token/"),
      body: {"username": user, "password": pass},
    );

    return jsonDecode(res.body)['access'];
  }
}

📤 Upload Service

Future uploadFile(String path, String token) async {
  var req = http.MultipartRequest(
    "POST",
    Uri.parse("http://127.0.0.1:8000/upload/")
  );

  req.headers['Authorization'] = 'Bearer $token';

  req.files.add(await http.MultipartFile.fromPath('file', path));

  await req.send();
}

📂 File List Screen

Future getFiles(String token) async {
  final res = await http.get(
    Uri.parse("http://127.0.0.1:8000/files/"),
    headers: {"Authorization": "Bearer $token"},
  );

  return jsonDecode(res.body);
}

🖼️ UI (Basit ama gerçek)

Column(
  children: [
    ElevatedButton(
      onPressed: pickAndUpload,
      child: Text("Dosya Yükle"),
    ),
    Expanded(
      child: ListView.builder(
        itemCount: files.length,
        itemBuilder: (_, i) => ListTile(
          title: Text(files[i]['title']),
        ),
      ),
    )
  ],
)

🎨 2. FİGMA UI TASARIM (GERÇEK APP)

Sana profesyonel mobil uygulama ekranlarını anlatıyorum 👇


📱 1. Login Screen

  • Logo üstte

  • Email / Şifre input

  • "Giriş Yap" butonu

  • Gradient arka plan


📱 2. Home Screen

  • AppBar: “Dosyalarım”

  • FloatingActionButton (+)

  • Liste halinde dosyalar


📱 3. Upload Screen

  • Dosya seç butonu

  • Dosya adı preview

  • Upload butonu

  • Progress bar


📱 4. File Detail Screen

  • Dosya adı

  • Tarih

  • “İndir” butonu

  • “Sil” butonu


🎯 Figma Design Özellikleri

🎨 Renk Paleti:

  • Primary: #4A90E2

  • Secondary: #50E3C2

  • Background: #F5F7FA

🔤 Font:

  • Google Fonts → Poppins

📐 UI Stil:

  • Modern

  • Rounded corners

  • Soft shadow








🚀 PRO DJANGO + FLUTTER UPLOAD SİSTEMİ

🔥 Bu versiyonda neler var?

✅ JWT (access + refresh token)
✅ Register / Login sistemi
✅ Kullanıcıya özel dosyalar
✅ Çoklu dosya upload
✅ Dosya silme
✅ Progress bar (Flutter)
✅ Clean Architecture (backend + frontend)
✅ Error handling
✅ API service katmanı


🧠 1. BACKEND (DJANGO PRO ARCHITECTURE)

📁 KLASÖR YAPISI

backend/
├── core/
├── apps/
│   ├── users/
│   └── uploads/
├── services/
├── api/
├── media/

🔐 JWT (Refresh Token Sistemi)

from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

urlpatterns = [
    path('api/token/', TokenObtainPairView.as_view()),
    path('api/token/refresh/', TokenRefreshView.as_view()),
]

👤 USER REGISTER API

class RegisterView(APIView):
    def post(self, request):
        user = User.objects.create_user(
            username=request.data['username'],
            password=request.data['password']
        )
        return Response({"message": "User created"})

📂 UPLOAD SERVICE (Clean Code)

👉 Business logic’i view’dan ayırıyoruz:

# services/upload_service.py

def create_upload(user, file, title):
    return Upload.objects.create(
        user=user,
        file=file,
        title=title
    )

📤 UPLOAD API (MULTIPLE SUPPORT)

class UploadView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        files = request.FILES.getlist('files')

        uploaded_files = []

        for f in files:
            obj = create_upload(request.user, f, request.data.get('title'))
            uploaded_files.append(obj.file.url)

        return Response({
            "files": uploaded_files
        })

📥 DOSYA LİSTELEME

class FileListView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        files = Upload.objects.filter(user=request.user)
        return Response([
            {
                "id": f.id,
                "file": f.file.url,
                "title": f.title
            } for f in files
        ])

🗑️ DOSYA SİLME

class DeleteFileView(APIView):
    permission_classes = [IsAuthenticated]

    def delete(self, request, id):
        file = Upload.objects.get(id=id, user=request.user)
        file.delete()
        return Response({"message": "Silindi"})

📱 2. FLUTTER PRO ARCHITECTURE

📁 KLASÖR YAPISI

lib/
├── models/
├── services/
├── providers/
├── screens/
├── widgets/

🧠 AUTH SERVICE

class AuthService {
  Future<Map> login(String user, String pass) async {
    final res = await http.post(
      Uri.parse("$baseUrl/api/token/"),
      body: {"username": user, "password": pass},
    );

    return jsonDecode(res.body);
  }
}

🔁 TOKEN REFRESH

Future<String> refreshToken(String refresh) async {
  final res = await http.post(
    Uri.parse("$baseUrl/api/token/refresh/"),
    body: {"refresh": refresh},
  );

  return jsonDecode(res.body)['access'];
}

📤 MULTI FILE UPLOAD + PROGRESS

Future uploadFiles(List<String> paths, String token) async {
  var request = http.MultipartRequest(
    'POST',
    Uri.parse("$baseUrl/upload/")
  );

  request.headers['Authorization'] = 'Bearer $token';

  for (var path in paths) {
    request.files.add(
      await http.MultipartFile.fromPath('files', path),
    );
  }

  var response = await request.send();

  response.stream.listen((value) {
    print("Yükleniyor...");
  });
}

📊 PROVIDER (STATE MANAGEMENT)

class FileProvider with ChangeNotifier {
  List files = [];

  void setFiles(data) {
    files = data;
    notifyListeners();
  }
}

🖼️ HOME SCREEN (REAL UI)

Column(
  children: [
    ElevatedButton(
      onPressed: pickAndUpload,
      child: Text("Dosya Yükle"),
    ),
    Expanded(
      child: ListView.builder(
        itemCount: provider.files.length,
        itemBuilder: (_, i) {
          var file = provider.files[i];

          return ListTile(
            title: Text(file['title']),
            trailing: IconButton(
              icon: Icon(Icons.delete),
              onPressed: () => deleteFile(file['id']),
            ),
          );
        },
      ),
    )
  ],
)

🎨 PRO UI (Figma seviyesinde)

🔥 Modern UX Özellikleri

  • Floating Action Button (+ Upload)

  • Swipe to delete

  • Loading spinner

  • Upload progress bar

  • Image preview


🔒 SECURITY (ÇOK ÖNEMLİ)

✅ Kullanıcı sadece kendi dosyasını görür
✅ JWT zorunlu
✅ Dosya boyut limiti
✅ Dosya tipi kontrolü


☁️ PRODUCTION (GERÇEK DÜNYA)

Bunu eklersen seviye uçar:

  • Nginx

  • Gunicorn

  • AWS S3 (media storage)

  • Cloudflare CDN


💥 SONUÇ

Bu proje:

🎓 GitHub’a koy → staj garantisi seviyesinde
💼 Freelance → para kazanabileceğin proje
🧠 Öğrenme → gerçek backend + mobil mimari




🔐 JWT güvenlik + 🖱️ Drag & Drop + 📊 Progress + ☁️ AWS S3

Bu rehber = gerçek production mimarisi


🔐 1. JWT ile GÜVENLİ UPLOAD (Django)

🎯 Amaç

  • Sadece giriş yapan kullanıcı upload yapabilsin

  • Token süresi dolarsa otomatik yenilensin


⚙️ settings.py (JWT ayarları)

from datetime import timedelta

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=30),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    "AUTH_HEADER_TYPES": ("Bearer",),
}

🧠 Güvenli Upload View

from rest_framework.permissions import IsAuthenticated

class SecureUploadView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        file = request.FILES.get('file')

        if not file:
            return Response({"error": "Dosya yok"}, status=400)

        if file.size > 5 * 1024 * 1024:
            return Response({"error": "Max 5MB"}, status=400)

        obj = Upload.objects.create(
            user=request.user,
            file=file,
            title=request.data.get('title')
        )

        return Response({
            "file": obj.file.url
        })

🔒 Flutter → Token ile istek

headers: {
  "Authorization": "Bearer $accessToken"
}

🔁 Token otomatik yenileme (ÇOK KRİTİK)

if (response.statusCode == 401) {
  accessToken = await refreshToken(refreshToken);
}

🖱️ 2. Drag & Drop Upload UI

📱 Flutter (Web & Desktop destekli)

import 'package:flutter_dropzone/flutter_dropzone.dart';

late DropzoneViewController controller;

DropzoneView(
  onCreated: (ctrl) => controller = ctrl,
  onDrop: (ev) async {
    final bytes = await controller.getFileData(ev);
    print("Dosya bırakıldı!");
  },
)

🎯 UX

✔ Dosyayı sürükle → bırak
✔ Otomatik upload başlar
✔ Progress gösterilir


📊 3. Progress Bar + AJAX Upload

📡 Flutter (gerçek progress)

var request = http.MultipartRequest(
  'POST',
  Uri.parse(uploadUrl),
);

var streamedResponse = await request.send();

streamedResponse.stream.listen((value) {
  print("yükleniyor...");
});

🧠 Daha profesyonel (yüzdelik progress)

import 'package:dio/dio.dart';

Dio dio = Dio();

await dio.post(
  uploadUrl,
  data: formData,
  onSendProgress: (sent, total) {
    double progress = sent / total;
    print("Progress: $progress");
  },
);

📊 UI

LinearProgressIndicator(value: progress)

☁️ 4. AWS S3 ENTEGRASYONU (PRO LEVEL)

📦 Paket

pip install boto3 django-storages

⚙️ settings.py

INSTALLED_APPS += ['storages']

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

AWS_ACCESS_KEY_ID = 'KEY'
AWS_SECRET_ACCESS_KEY = 'SECRET'
AWS_STORAGE_BUCKET_NAME = 'bucket-name'

AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None

🎯 Sonuç

Artık dosyalar:

❌ local değil
✅ AWS S3 üzerinde saklanır


📤 Upload sonrası URL

{
  "file": "https://bucket.s3.amazonaws.com/uploads/file.jpg"
}

🔥 FULL SİSTEM AKIŞI

Flutter (Drag & Drop + Progress)
        ↓
JWT Token ile API isteği
        ↓
Django (Auth kontrol)
        ↓
AWS S3 (dosya kaydı)
        ↓
URL geri döner
        ↓
Flutter UI güncellenir





Bu sistem = şirketlerde kullanılan gerçek mimari.


🚀 ULTIMATE PROJE (Django + Flutter + S3 + Docker)

🔥 Bu projede NELER VAR?

✅ JWT (access + refresh + auto refresh)
✅ Drag & Drop upload (Flutter Web dahil)
✅ Progress bar (gerçek zamanlı)
✅ AWS S3 (cloud storage)
✅ Docker (tek komutla kurulum)
✅ Nginx (production server)
✅ Rate limiting + güvenlik
✅ Clean Architecture (backend + frontend)
✅ Admin dashboard (istatistikli)


1. SİSTEM MİMARİSİ

Flutter App / Web
        ↓
Nginx (Reverse Proxy)
        ↓
Django API (Gunicorn)
        ↓
Redis (Cache + Rate Limit)
        ↓
PostgreSQL
        ↓
AWS S3 (Dosyalar)

🐳 2. DOCKER SETUP (TEK KOMUTLA ÇALIŞAN SİSTEM)

📁 docker-compose.yml

version: "3.9"

services:
  web:
    build: .
    command: gunicorn config.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - .:/app
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass

  redis:
    image: redis:7

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - web

⚙️ 3. DJANGO PRODUCTION SETTINGS

DEBUG = False

ALLOWED_HOSTS = ["*"]

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": "app",
        "USER": "user",
        "PASSWORD": "pass",
        "HOST": "db",
        "PORT": 5432,
    }
}

🔒 4. RATE LIMIT (GÜVENLİK)

📦 Paket

pip install django-ratelimit

🔐 Kullanım

from django_ratelimit.decorators import ratelimit

@ratelimit(key='ip', rate='5/m', block=True)
def upload_view(request):
    ...

☁️ 5. AWS S3 (FINAL STORAGE)

DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'

📊 6. ADMIN DASHBOARD (PRO)

Özellikler:

  • 📈 Günlük upload sayısı

  • 👤 Kullanıcı bazlı istatistik

  • 📂 Dosya türü analizi

  • 🕒 Zaman grafikleri


📱 7. FLUTTER (ULTIMATE UI)

🎨 Ekranlar

🔐 Login Screen

  • JWT login

  • Error handling

🏠 Dashboard

  • Dosya listesi

  • Arama + filtre

📤 Upload Screen

  • Drag & Drop

  • Progress bar

📄 File Detail

  • Preview (image/pdf)

  • Download

  • Delete


📊 PROGRESS BAR (GERÇEK)

onSendProgress: (sent, total) {
  setState(() {
    progress = sent / total;
  });
}

🖱️ DRAG & DROP UX

  • Dosyayı sürükle → bırak

  • Otomatik upload

  • Progress animasyonu


🔁 TOKEN AUTO REFRESH FLOW

Request → 401
    ↓
Refresh Token
    ↓
Yeni Access Token
    ↓
Retry Request

⚡ NGINX CONFIG (ÖZET)

server {
    listen 80;

    location / {
        proxy_pass http://web:8000;
    }
}

🎯 DEPLOY (GERÇEK SUNUCU)

🌐 Nerede çalıştırabilirsin?

  • DigitalOcean

  • Amazon Web Services

  • Railway







Yorumlar

Bu blogdaki popüler yayınlar

Dart Uygulama Sınavı: Pardus ETAP 23 Kurulum Otomasyonu

Dart Programlama Dil Uygulama Sınavı Çalışma Soruları

Pardus Üzerinde Flutter Geliştirme Ortamı Kurulumu