Pertama kali coba Django, saya langsung kaget betapa cepatnya bisa bikin web app yang jalan. Dalam hitungan jam, dari nol sampai ada CRUD lengkap dengan admin panel. Kalau kamu udah kenal Python tapi belum pernah nyoba web framework-nya, Django itu jawaban paling solid. Framework ini dipercaya oleh Instagram, Pinterest, dan Mozilla - jadi soal skala, nggak perlu diragukan lagi.
Tutorial ini bakal nuntun kamu dari install Django sampai bikin aplikasi To-Do List yang fungsional. Kita bakal bahas setup project, bikin model, view, template, dan cara menjalankan semuanya. Semua code di sini udah dicoba di Python 3.12 dan Django 5.1.
Sebelum masuk ke code, penting buat ngerti kenapa Django jadi pilihan banyak developer. Django itu "batteries-included" - artinya udah include banyak fitur yang biasanya harus kamu install terpisah di framework lain.
Dibanding framework Python lain kayak Flask atau FastAPI, Django lebih cocok buat project yang butuh banyak fitur standar. Flask itu minimalis (kamu nambah sendiri yang kamu butuh), sedangkan Django langsung kasih semua. Kalau Flask itu seperti beli tanah kosong, Django itu udah ada fondasi dan dindingnya - tinggal dekorasi.
Langkah pertama tentu saja install Django. Pastikan kamu udah punya Python 3.8+ terinstall. Kalau belum, baca dulu tutorial tentang Python Virtual Environment supaya project kamu rapi.
# Buat virtual environment
python3 -m venv django-env
# Aktifkan virtual environment
# Linux/Mac:
source django-env/bin/activate
# Windows:
django-env\Scripts\activate
# Install Django
pip install django
# Cek versi Django yang terinstall
python -m django --version
Kalau outputnya sesuatu seperti 5.1.4, berarti install berhasil. Sekarang bikin project baru:
# Buat project Django baru
django-admin startproject todoproject
# Masuk ke folder project
cd todoproject
# Lihat struktur project
ls -la
Django otomatis generate struktur folder seperti ini:
todoproject/
manage.py # Command-line utility
todoproject/
__init__.py # Package marker
settings.py # Konfigurasi project
urls.py # URL routing
wsgi.py # WSGI entry point
asgi.py # ASGI entry point
manage.py itu command center kamu. Semua perintah Django dijalankan lewat file ini - mulai dari bikin database, bikin user admin, sampai menjalankan server.
Sebelum bikin apapun, coba jalankan server dulu buat pastikan semuanya jalan:
# Jalankan development server
python manage.py runserver
# Output:
# Starting development server at http://127.0.0.1:8000/
# Quit the server with CONTROL-C.
Buka browser, akses http://127.0.0.1:8000/. Kalau muncul halaman roket Django berwarna biru, berarti setup berhasil. Kalau error, cek apakah ada port yang sudah dipakai - coba python manage.py runserver 8080.
Django punya konsep "project" dan "app". Project itu rumahnya, app itu ruangan-ruangannya. Satu project bisa punya banyak app, masing-masing menangani fitur berbeda.
# Bikin app baru bernama 'todo'
python manage.py startapp todo
Ini bikin folder todo/ dengan file-file penting:
todo/
__init__.py
admin.py # Konfigurasi admin panel
apps.py # Konfigurasi app
migrations/ # Database migrations
models.py # Database models
tests.py # Unit tests
views.py # View functions/classes
Jangan lupa daftarkan app baru ini di settings.py:
# todoproject/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'todo', # Tambahkan ini
]
Model di Django itu representasi dari tabel database. Kamu definisikan sebagai Python class, dan Django yang bikin SQL-nya otomatis. Ini yang bikin Django powerful - kamu nggak perlu nulis CREATE TABLE sama sekali.
# todo/models.py
from django.db import models
class Task(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.title
Penjelasan field di atas:
CharField - Teks pendek dengan batas karakter (wajib max_length)TextField - Teks panjang tanpa batas, blank=True artinya boleh kosongBooleanField - True/False, default-nya False (belum selesai)DateTimeField - Tanggal dan waktu, auto_now_add=True otomatis set saat createordering = ['-created_at'] - Data terbaru muncul duluanSetelah definisi model, kamu perlu "migrate" supaya perubahan diterapkan ke database. Django menggunakan SQLite sebagai database default - cocok untuk development.
# Buat migration file dari model yang baru dibuat
python manage.py makemigrations todo
# Output: Migrations for 'todo':
# todo/migrations/0001_initial.py
# - Create model Task
# Terapkan migration ke database
python manage.py migrate
# Output: Applying todo.0001_initial... OK
Kalau mau lihat SQL yang dijalankan Django secara internal, pakai perintah:
python manage.py sqlmigrate todo 0001
Ini nampilin CREATE TABLE SQL yang sebenarnya. Menarik buat ngerti apa yang terjadi di balik layar.
Salah satu fitur terbaik Django adalah admin panel. Cuma dengan beberapa baris code, kamu udah punya dashboard buat manage data.
# todo/admin.py
from django.contrib import admin
from .models import Task
@admin.register(Task)
class TaskAdmin(admin.ModelAdmin):
list_display = ['title', 'completed', 'created_at']
list_filter = ['completed', 'created_at']
search_fields = ['title', 'description']
list_editable = ['completed']
Bikin superuser dulu buat bisa login ke admin:
python manage.py createsuperuser
# Ikuti prompt:
# Username: admin
# Email: [email protected]
# Password: ********
Jalankan server lagi, buka http://127.0.0.1:8000/admin/, login dengan akun yang baru dibuat. Kamu bakal lihat halaman admin dengan "Tasks" yang siap dikelola. Tambah beberapa task dari sini supaya ada data buat ditampilkan.
View itu tempat logika aplikasi berjalan. Di Django ada dua cara bikin view: function-based dan class-based. Kita pakai function-based dulu supaya lebih mudah dipahami.
# todo/views.py
from django.shortcuts import render, redirect, get_object_or_404
from .models import Task
def task_list(request):
tasks = Task.objects.all()
return render(request, 'todo/task_list.html', {'tasks': tasks})
def task_create(request):
if request.method == 'POST':
title = request.POST.get('title')
description = request.POST.get('description', '')
if title:
Task.objects.create(title=title, description=description)
return redirect('task_list')
return render(request, 'todo/task_form.html')
def task_toggle(request, task_id):
task = get_object_or_404(Task, id=task_id)
task.completed = not task.completed
task.save()
return redirect('task_list')
def task_delete(request, task_id):
task = get_object_or_404(Task, id=task_id)
task.delete()
return redirect('task_list')
Fungsi render() menggabungkan template HTML dengan data dari view. Fungsi get_object_or_404() itu shortcut yang otomatis return halaman 404 kalau data nggak ketemu - jadi nggak perlu handle error manual.
URL routing di Django itu seperti peta - kamu definisikan URL pattern yang mengarah ke view tertentu. Ada dua level routing: project-level dan app-level.
# todo/urls.py (BUAT FILE BARU)
from django.urls import path
from . import views
urlpatterns = [
path('', views.task_list, name='task_list'),
path('create/', views.task_create, name='task_create'),
path('toggle//', views.task_toggle, name='task_toggle'),
path('delete//', views.task_delete, name='task_delete'),
]
# todoproject/urls.py (EDIT FILE YANG UDAH ADA)
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('todo.urls')),
]
include('todo.urls') memungkinkan setiap app punya URL routing sendiri. Ini bikin project tetap rapi walaupun punya banyak app.
Template Django menggunakan bahasa template sendiri yang mirip HTML tapi dengan tag khusus. Bikin folder templates di dalam app:
mkdir -p todo/templates/todo
Kenapa nested todo/ dua kali? Karena Django mencari template berdasarkan nama app + nama file. Dengan struktur ini, kamu bisa punya todo/templates/todo/task_list.html dan blog/templates/blog/task_list.html tanpa konflik.
<!-- todo/templates/todo/task_list.html -->
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo App - Django</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Segoe UI', sans-serif; background: #f5f5f5; padding: 20px; }
.container { max-width: 600px; margin: 0 auto; }
h1 { color: #333; margin-bottom: 20px; }
.task-form { background: #fff; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.task-form input[type="text"] { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 10px; }
.task-form textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 10px; resize: vertical; }
.btn { padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; font-size: 14px; }
.btn-primary { background: #4CAF50; color: #fff; }
.btn-danger { background: #f44336; color: #fff; }
.btn-success { background: #2196F3; color: #fff; }
.task-item { background: #fff; padding: 15px; border-radius: 8px; margin-bottom: 10px; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
.task-item.completed { opacity: 0.6; }
.task-item.completed .task-title { text-decoration: line-through; }
.task-title { font-size: 16px; font-weight: 500; }
.task-date { font-size: 12px; color: #999; }
.task-actions a { margin-left: 8px; }
</style>
</head>
<body>
<div class="container">
<h1>My Todo List</h1>
<div class="task-form">
<form method="POST" action="{% url 'task_create' %}">
{% csrf_token %}
<input type="text" name="title" placeholder="Task baru..." required>
<textarea name="description" placeholder="Deskripsi (opsional)" rows="2"></textarea>
<button type="submit" class="btn btn-primary">Tambah Task</button>
</form>
</div>
{% for task in tasks %}
<div class="task-item {% if task.completed %}completed{% endif %}">
<div>
<div class="task-title">{{ task.title }}</div>
{% if task.description %}
<div style="color:#666;font-size:13px;margin-top:4px;">{{ task.description }}</div>
{% endif %}
<div class="task-date">{{ task.created_at|date:"d M Y H:i" }}</div>
</div>
<div class="task-actions">
<a href="{% url 'task_toggle' task.id %}" class="btn btn-success">
{% if task.completed %}Undo{% else %}Done{% endif %}
</a>
<a href="{% url 'task_delete' task.id %}" class="btn btn-danger"
onclick="return confirm('Yakin hapus?')">Hapus</a>
</div>
</div>
{% empty %}
<p style="text-align:center;color:#999;padding:20px;">Belum ada task. Tambahkan yang baru!</p>
{% endfor %}
</div>
</body>
</html>
Beberapa hal penting dari template di atas:
{% csrf_token %} - Wajib ada di setiap form POST. Ini CSRF protection bawaan Django{% url 'task_create' %} - Generate URL dari nama route. Kalau URL berubah, template otomatis menyesuaikan{% for task in tasks %} - Loop Python di template{% if task.completed %} - Conditional di template{{ task.created_at|date:"d M Y H:i" }} - Format tanggal pakai Django template filter{% empty %} - Block yang ditampilkan kalau list kosong<!-- todo/templates/todo/task_form.html -->
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<title>Tambah Task - Todo App</title>
</head>
<body>
<h1>Tambah Task Baru</h1>
<form method="POST">
{% csrf_token %}
<p><input type="text" name="title" placeholder="Judul task" required></p>
<p><textarea name="description" placeholder="Deskripsi"></textarea></p>
<p><button type="submit">Simpan</button></p>
</form>
<a href="{% url 'task_list' %}">Kembali</a>
</body>
</html>
Sekarang saatnya test! Pastikan server masih jalan, lalu buka browser:
# Kalau server belum jalan
python manage.py runserver
# Akses di browser:
# http://127.0.0.1:8000/
Kamu bakal lihat halaman Todo List dengan form tambah task di atas. Coba tambahkan beberapa task, tandai sebagai selesai, dan hapus. Semua CRUD (Create, Read, Update, Delete) udah jalan dengan cuma sekitar 100 baris code!
Django punya shell interaktif yang sangat berguna buat testing dan debugging. Bedanya dengan Python shell biasa, Django shell udah load semua model dan konfigurasi.
python manage.py shell
# Di dalam shell:
>>> from todo.models import Task
>>> Task.objects.all()
, ]>
>>> Task.objects.filter(completed=True)
]>
>>> Task.objects.create(title='Task dari shell', description='Testing via shell')
>>> Task.objects.count()
3
Django ORM sangat intuitif kalau kamu udah kenal Python. Filter, exclude, annotate, aggregate - semua bisa dilakukan dengan syntax yang clean.
Kadang kamu butuh logic tambahan di template. Django memungkinkan kamu bikin custom template tags dan filters:
# todo/templatetags/todo_tags.py (BUAT FILE BARU)
# Jangan lupa buat __init__.py di folder templatetags
from django import template
from todo.models import Task
register = template.Library()
@register.simple_tag
def pending_count():
return Task.objects.filter(completed=False).count()
@register.filter
def truncate_words_custom(value, num=10):
words = value.split()
if len(words) > num:
return ' '.join(words[:num]) + '...'
return value
Di template, pakai seperti ini:
{% load todo_tags %}
<p>Task yang belum selesai: {% pending_count %}</p>
<p>{{ task.description|truncate_words_custom:15 }}</p>
Django punya sistem static files yang rapi. Untuk development, cukup taruh file statis di folder todo/static/todo/:
mkdir -p todo/static/todo/css
mkdir -p todo/static/todo/js
/* todo/static/todo/css/style.css */
body { font-family: 'Segoe UI', Tahoma, sans-serif; }
.task-item { transition: all 0.3s ease; }
.task-item:hover { transform: translateX(5px); }
Load di template:
{% load static %}
<link rel="stylesheet" href="{% static 'todo/css/style.css' %}">
Untuk production, kamu perlu jalankan python manage.py collectstatic yang mengumpulkan semua static files ke satu folder yang bisa di-serve oleh nginx atau web server lain.
Django bisa kamu extend dengan custom management commands. Ini sangat berguna buat task automation:
# todo/management/commands/clear_completed.py
# Buat folder: todo/management/ dan todo/management/commands/
# Jangan lupa __init__.py di kedua folder
from django.core.management.base import BaseCommand
from todo.models import Task
class Command(BaseCommand):
help = 'Hapus semua task yang sudah selesai'
def handle(self, *args, **options):
count = Task.objects.filter(completed=True).count()
Task.objects.filter(completed=True).delete()
self.stdout.write(
self.style.SUCCESS(f'Berhasil menghapus {count} task yang sudah selesai')
)
Jalankan dengan:
python manage.py clear_completed
# Output: Berhasil menghapus 3 task yang sudah selesai
pip install djangorestframework dan kamu bisa expose model sebagai REST endpoint dalam hitungan menitsettings/base.py, settings/local.py, settings/production.py supaya konfigurasi environment nggak campur adukDjango itu framework yang sangat mature dan well-documented. Dari tutorial ini, kamu udah ngerti cara bikin project, definisi model, bikin view, dan membuat template. Todo app yang kita buat cuma permukaan - Django bisa jauh lebih powerful dari ini.
Langkah selanjutnya yang saya sarankan: coba bikin project kedua dengan fitur authentication (login/register), lalu explore Django REST Framework buat bikin API. Kalau udah familiar, coba deploy ke VPS dengan Gunicorn dan Nginx.
Punya pertanyaan atau stuck di step tertentu? Tulis di kolom komentar di bawah, saya bantu selesaikan!