Setup Proyek
Buat Proyek & App
pip install django django-admin startproject mysite cd mysite python manage.py startapp blog
Perintah Umum
runserverJalankan dev server di port 8000
makemigrationsBuat file migrasi dari perubahan model
migrateTerapkan migrasi ke database
createsuperuserBuat admin superuser
shellShell Python interaktif dengan Django
testJalankan test suite
Struktur Proyek
manage.pyTitik masuk CLI
settings.pyKonfigurasi proyek
urls.pyKonfigurasi URL root
wsgi.py / asgi.pyTitik masuk server
apps/models.pyModel database
apps/views.pyHandler request
Model
Definisi Model
from django.db import models class Post(models.Model): title = models.CharField(max_length=200) body = models.TextField() created = models.DateTimeField(auto_now_add=True) published = models.BooleanField(default=False)
Tipe Field
CharField(max_length=N)Teks pendek (wajib max_length)
TextField()Teks panjang (tanpa batas)
IntegerField()Nilai integer
FloatField()Angka floating point
BooleanField()True / False
DateTimeField()Tanggal dan waktu
EmailField()Email dengan validasi
FileField(upload_to='')Upload file
Relasi
author = models.ForeignKey( User, on_delete=models.CASCADE ) tags = models.ManyToManyField(Tag, blank=True) profile = models.OneToOneField(User, on_delete=models.CASCADE)
Meta & Method
class Meta: ordering = ['-created'] verbose_name_plural = 'posts' def __str__(self): return self.title
View
Function-Based View
from django.shortcuts import render, get_object_or_404 def post_list(request): posts = Post.objects.filter(published=True) return render(request, 'blog/list.html', {'posts': posts})
Class-Based View
from django.views.generic import ListView, DetailView class PostListView(ListView): model = Post template_name = 'blog/list.html' context_object_name = 'posts' paginate_by = 10
CBV Umum
ListViewTampilkan daftar objek
DetailViewTampilkan satu objek
CreateViewForm untuk membuat objek
UpdateViewForm untuk mengedit objek
DeleteViewKonfirmasi dan hapus objek
TemplateViewRender template (tanpa model)
JSON Response
from django.http import JsonResponse def api_posts(request): data = list(Post.objects.values('id', 'title')) return JsonResponse(data, safe=False)
Template
Sintaks Template
{{ variable }} {{ post.title|truncatewords:30 }} {% if user.is_authenticated %}

Welcome, {{ user.username }}!

{% endif %}
Loop & Kondisi
{% for post in posts %}

{{ post.title }}

{% if forloop.last %}
{% endif %} {% empty %}

No posts yet.

{% endfor %}
Pewarisan Template
{# base.html #} {% block content %}{% endblock %} {# child.html #} {% extends "base.html" %} {% block content %}

Hello

{% endblock %}
Filter Umum
|date:"Y-m-d"Format tanggal
|default:"N/A"Fallback untuk nilai kosong
|lengthHitung item dalam list
|truncatewords:NBatasi ke N kata
|safeTandai sebagai HTML aman (tanpa escaping)
|slugifyString huruf kecil yang aman untuk URL
URL
Pola URL
from django.urls import path, include urlpatterns = [ path('', views.index, name='index'), path('post//', views.detail, name='detail'), path('blog/', include('blog.urls')), ]
Converter Path
<int:pk>Integer (mis. 42)
<str:slug>String tanpa slash
<slug:slug>Slug (huruf, angka, tanda hubung)
<uuid:id>Format UUID
<path:rest>Path lengkap termasuk slash
URL Terbalik
from django.urls import reverse url = reverse('detail', kwargs={'pk': 1}) # In templates: {% url 'detail' pk=post.pk %}
Form
Model Form
from django import forms class PostForm(forms.ModelForm): class Meta: model = Post fields = ['title', 'body', 'published']
Proses Form di View
def create_post(request): form = PostForm(request.POST or None) if form.is_valid(): post = form.save(commit=False) post.author = request.user post.save() return redirect('detail', pk=post.pk) return render(request, 'blog/form.html', {'form': form})
Form di Template
{% csrf_token %} {{ form.as_p }}
Validasi
def clean_title(self): title = self.cleaned_data['title'] if len(title) < 5: raise forms.ValidationError("Title too short.") return title
Admin
Daftarkan Model
from django.contrib import admin from .models import Post @admin.register(Post) class PostAdmin(admin.ModelAdmin): list_display = ['title', 'author', 'created', 'published'] list_filter = ['published', 'created'] search_fields = ['title', 'body']
Opsi Admin
list_displayKolom dalam tampilan list
list_filterOpsi filter sidebar
search_fieldsField yang bisa dicari
prepopulated_fieldsIsi otomatis (mis. slug dari title)
readonly_fieldsTidak bisa diedit di admin
orderingUrutan sort default
Query ORM
Query Dasar
Post.objects.all() # all records Post.objects.get(pk=1) # single (raises if missing) Post.objects.filter(published=True) # queryset Post.objects.exclude(draft=True) # exclude matches Post.objects.count() # total count
Field Lookup
field__exactKecocokan tepat (default)
field__icontainsMengandung (case-insensitive)
field__gt / __ltLebih besar / lebih kecil dari
field__gte / __lteLebih besar/kecil atau sama dengan
field__in=[1,2,3]Nilai ada dalam daftar
field__isnull=TrueBernilai NULL
field__startswithDimulai dengan string
field__range=(a,b)Antara a dan b (inklusif)
Chaining & Agregasi
from django.db.models import Q, Count, Avg Post.objects.filter( Q(title__icontains='django') | Q(body__icontains='django') ).order_by('-created')[:10] Post.objects.aggregate(avg_views=Avg('views'))
Buat, Perbarui, Hapus
post = Post.objects.create(title='New', body='...') post.title = 'Updated' post.save() Post.objects.filter(draft=True).update(published=False) post.delete()
Autentikasi
Login / Logout
from django.contrib.auth import authenticate, login, logout user = authenticate(request, username='admin', password='pw') if user is not None: login(request, user)
Lindungi View
from django.contrib.auth.decorators import login_required @login_required def dashboard(request): return render(request, 'dashboard.html')
URL Auth
# urls.py path('accounts/', include('django.contrib.auth.urls')) # Provides: login, logout, password_change, password_reset
Auth di Template
{% if user.is_authenticated %}

Hi, {{ user.username }}

Logout {% else %} Login {% endif %}
Pengaturan
Pengaturan Utama
DEBUGTrue untuk dev, False untuk produksi
ALLOWED_HOSTSDaftar hostname yang valid
SECRET_KEYKunci signing kriptografis (jaga kerahasiaannya)
DATABASESEngine DB, nama, host, kredensial
INSTALLED_APPSDaftar app yang terdaftar
STATIC_URLPrefix URL untuk file statis
MEDIA_URL / MEDIA_ROOTPath file yang diunggah pengguna
Konfigurasi Database
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'mydb', 'USER': 'dbuser', 'HOST': 'localhost', 'PORT': '5432', } }
File Statis
STATIC_URL = '/static/' STATICFILES_DIRS = [BASE_DIR / 'static'] # In templates: {% load static %} #