Python

Django Web Framework untuk Pemula

Tutorial lengkap belajar Django dari nol β€” MVT pattern, models, views, templates, admin, forms, ORM, dan quiz interaktif dengan contoh kode praktis

1. Pengenalan Django

Django adalah web framework Python yang bersifat open-source dan baterai-include (semua fitur sudah tersedia). Dikembangkan pertama kali pada tahun 2005 oleh Adrian Holovaty dan Simon Willison, Django menjadi salah satu framework web paling populer dan banyak digunakan di dunia.

Django digunakan oleh banyak perusahaan besar seperti Instagram, Pinterest, Mozilla, Disqus, dan Bitbucket. Filosofi Django adalah "Don't Repeat Yourself" (DRY) dan "Batteries Included", artinya semua fitur yang dibutuhkan sudah tersedia built-in.

Mengapa Memilih Django?

Keunggulan Penjelasan
Batteries IncludedORM, admin panel, authentication, forms, semua built-in
SecurityProteksi bawaan terhadap CSRF, XSS, SQL Injection, dan clickjacking
ORM KuatBekerja dengan database tanpa menulis SQL langsung
Admin PanelPanel admin otomatis untuk mengelola data
ScalableBisa menangani traffic tinggi (Instagram menggunakan Django)
DokumentasiDokumentasi lengkap dan komunitas besar
Diagram: Arsitektur MVT Django
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               DJANGO MVT PATTERN                     β”‚
β”‚                                                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚
β”‚  β”‚          β”‚     β”‚          β”‚     β”‚          β”‚     β”‚
β”‚  β”‚ TEMPLATE │◄────│  VIEW    │────►│  MODEL   β”‚     β”‚
β”‚  β”‚  (HTML)  β”‚     β”‚ (Python) β”‚     β”‚  (Data)  β”‚     β”‚
β”‚  β”‚          β”‚     β”‚          β”‚     β”‚          β”‚     β”‚
β”‚  β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜     β”‚
β”‚       β”‚                β”‚                β”‚            β”‚
β”‚       β”‚          β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”     β”‚
β”‚       β”‚          β”‚    URL    β”‚    β”‚  DATABASE  β”‚     β”‚
β”‚       β”‚          β”‚  Router   β”‚    β”‚ (PostgreSQLβ”‚     β”‚
β”‚       β”‚          β”‚           β”‚    β”‚  /SQLite)  β”‚     β”‚
β”‚       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”˜            β”‚     β”‚
β”‚                                                       β”‚
β”‚  Request: User β†’ URL β†’ View β†’ Model β†’ DB              β”‚
β”‚  Response: DB β†’ Model β†’ View β†’ Template β†’ User        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Instalasi dan Setup Proyek

Mari kita mulai dengan menginstal Django dan membuat proyek pertama.

Membuat Virtual Environment

Bash
# Buat folder proyek
mkdir belajar-django && cd belajar-django

# Buat virtual environment
python -m venv venv

# Aktifkan virtual environment
# Windows:
venv\Scripts\activate
# macOS/Linux:
source venv/bin/activate

# Instal Django
pip install django

# Verifikasi instalasi
python -m django --version
# Output: 5.0.6

Membuat Proyek dan Aplikasi

Bash
# Buat proyek Django baru
django-admin startproject mysite .

# Buat aplikasi di dalam proyek
python manage.py startapp blog

# Jalankan server development
python manage.py runserver
# Output:
# Starting development server at http://127.0.0.1:8000/

# Buat migrasi database
python manage.py migrate

# Buat superuser untuk admin
python manage.py createsuperuser

Struktur Proyek

File Structure
mysite/
β”œβ”€β”€ manage.py              ← Utility commands
β”œβ”€β”€ mysite/                ← Konfigurasi proyek
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ settings.py        ← Pengaturan proyek
β”‚   β”œβ”€β”€ urls.py            ← URL routing utama
β”‚   β”œβ”€β”€ asgi.py
β”‚   └── wsgi.py
└── blog/                  ← Aplikasi blog
    β”œβ”€β”€ __init__.py
    β”œβ”€β”€ admin.py           ← Konfigurasi admin
    β”œβ”€β”€ apps.py            ← Konfigurasi aplikasi
    β”œβ”€β”€ migrations/        ← Database migrations
    β”œβ”€β”€ models.py          ← Definisi model/data
    β”œβ”€β”€ tests.py           ← Unit tests
    β”œβ”€β”€ urls.py            ← URL routing aplikasi
    └── views.py           ← Logika tampilan

Konfigurasi settings.py

Python β€” settings.py
# mysite/settings.py β€” Tambahkan aplikasi 'blog'
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',  # ← Tambahkan ini
]

# Bahasa dan zona waktu Indonesia
LANGUAGE_CODE = 'id-id'
TIME_ZONE = 'Asia/Jakarta'
USE_I18N = True
USE_TZ = True

# Bahasa Indonesia untuk template
LOCALE_PATHS = [BASE_DIR / 'locale']
πŸ’‘ Tips

Setiap aplikasi Django harus didaftarkan di INSTALLED_APPS pada settings.py. Tanpa itu, Django tidak akan mengenali model, template, dan URL dari aplikasi tersebut.

3. Memahami MVT Pattern

Django menggunakan pola arsitektur MVT (Model-View-Template) yang mirip dengan MVC (Model-View-Controller) tetapi dengan penamaan yang sedikit berbeda.

MVC (Lain) MVT (Django) Fungsi
ModelModelStruktur data dan logika database
ViewTemplateTampilan HTML yang dikirim ke pengguna
ControllerViewLogika bisnis β€” memproses request dan mengembalikan response

Alur Request dalam Django

Alur Request
# Alur request Django:
#
# 1. User mengakses URL (misal: /blog/artikel/1/)
#       ↓
# 2. URL Dispatcher mencocokkan URL dengan pattern
#    urls.py β†’ path('artikel/<int:id>/', views.detail_artikel)
#       ↓
# 3. View function dipanggil
#    views.py β†’ def detail_artikel(request, id)
#       ↓
# 4. View mengambil data dari Model (database)
#    models.py β†’ Artikel.objects.get(id=id)
#       ↓
# 5. View merender Template dengan data
#    templates β†’ render(request, 'detail.html', context)
#       ↓
# 6. HTML dikembalikan ke browser user
#    HttpResponse β†’ <html>...</html>

4. Models: Mendefinisikan Data

Model adalah representasi dari data di database. Setiap model Django merepresentasikan satu tabel di database. Django ORM akan otomatis membuat tabel SQL berdasarkan definisi model.

Mendefinisikan Model

Python β€” blog/models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone

class Kategori(models.Model):
    nama = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)
    deskripsi = models.TextField(blank=True)

    class Meta:
        verbose_name_plural = "Kategori"
        ordering = ['nama']

    def __str__(self):
        return self.nama

class Artikel(models.Model):
    STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('published', 'Diterbitkan'),
    ]

    judul = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    penulis = models.ForeignKey(User, on_delete=models.CASCADE)
    kategori = models.ForeignKey(Kategori, on_delete=models.SET_NULL, null=True)
    konten = models.TextField()
    gambar = models.ImageField(upload_to='artikel/', blank=True)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    tags = models.ManyToManyField('Tag', blank=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name_plural = "Artikel"

    def __str__(self):
        return self.judul

    def get_absolute_url(self):
        return f'/blog/artikel/{self.slug}/'

class Tag(models.Model):
    nama = models.CharField(max_length=50, unique=True)

    class Meta:
        verbose_name_plural = "Tag"

    def __str__(self):
        return self.nama

class Komentar(models.Model):
    artikel = models.ForeignKey(Artikel, on_delete=models.CASCADE, related_name='komentar')
    nama = models.CharField(max_length=100)
    email = models.EmailField()
    isi = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    aktif = models.BooleanField(default=True)

    class Meta:
        ordering = ['created_at']

    def __str__(self):
        return f'Komentar oleh {self.nama} pada {self.artikel}'

Menjalankan Migrasi

Bash
# Buat file migrasi berdasarkan model
python manage.py makemigrations blog
# Output: Migrations for 'blog':
#   blog/migrations/0001_initial.py
#     - Create model Kategori
#     - Create model Tag
#     - Create model Artikel
#     - Create model Komentar

# Jalankan migrasi ke database
python manage.py migrate
# Output: Applying blog.0001_initial... OK

# Cek status migrasi
python manage.py showmigrations

# SQL yang dihasilkan (opsional, untuk debugging)
python manage.py sqlmigrate blog 0001

Tipe Field Django

Field Tipe SQL Contoh
CharFieldVARCHARCharField(max_length=100)
TextFieldTEXTTextField()
IntegerFieldINTIntegerField(default=0)
FloatFieldFLOATFloatField()
BooleanFieldBOOLEANBooleanField(default=True)
DateFieldDATEDateField(auto_now_add=True)
EmailFieldVARCHAREmailField()
SlugFieldVARCHARSlugField(unique=True)
ImageFieldVARCHARImageField(upload_to='img/')
ForeignKeyINT (FK)ForeignKey(Model, on_delete=CASCADE)

5. Views: Logika Aplikasi

View adalah fungsi atau class yang menerima HTTP request dan mengembalikan HTTP response. View berisi logika bisnis aplikasi β€” mengambil data dari model dan merender template.

Function-Based Views

Python β€” blog/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse, JsonResponse
from .models import Artikel, Kategori
from .forms import ArtikelForm, KomentarForm

# View sederhana β€” mengembalikan HTML
def beranda(request):
    artikel_terbaru = Artikel.objects.filter(
        status='published'
    ).order_by('-created_at')[:5]

    kategori_list = Kategori.objects.all()

    context = {
        'artikel_list': artikel_terbaru,
        'kategori_list': kategori_list,
        'judul_halaman': 'Beranda Blog',
    }
    return render(request, 'blog/beranda.html', context)

# View detail artikel
def detail_artikel(request, slug):
    artikel = get_object_or_404(Artikel, slug=slug, status='published')
    komentar_list = artikel.komentar.filter(aktif=True)
    form_komentar = KomentarForm()

    context = {
        'artikel': artikel,
        'komentar_list': komentar_list,
        'form_komentar': form_komentar,
    }
    return render(request, 'blog/detail.html', context)

# View berdasarkan kategori
def kategori_detail(request, slug):
    kategori = get_object_or_404(Kategori, slug=slug)
    artikel_list = kategori.artikel_set.filter(status='published')

    context = {
        'kategori': kategori,
        'artikel_list': artikel_list,
    }
    return render(request, 'blog/kategori.html', context)

# View untuk membuat artikel baru
def buat_artikel(request):
    if request.method == 'POST':
        form = ArtikelForm(request.POST, request.FILES)
        if form.is_valid():
            artikel = form.save(commit=False)
            artikel.penulis = request.user
            artikel.save()
            return redirect('blog:detail', slug=artikel.slug)
    else:
        form = ArtikelForm()

    return render(request, 'blog/buat_artikel.html', {'form': form})

# View JSON API
def api_artikel(request):
    artikel_list = list(
        Artikel.objects.filter(status='published')
        .values('judul', 'slug', 'created_at')[:10]
    )
    return JsonResponse({'artikel': artikel_list})

Class-Based Views

Python β€” CBV
from django.views.generic import ListView, DetailView, CreateView
from django.urls import reverse_lazy
from .models import Artikel
from .forms import ArtikelForm

# ListView β€” menampilkan daftar
class ArtikelListView(ListView):
    model = Artikel
    template_name = 'blog/artikel_list.html'
    context_object_name = 'artikel_list'
    paginate_by = 10

    def get_queryset(self):
        return Artikel.objects.filter(status='published')

# DetailView β€” menampilkan detail
class ArtikelDetailView(DetailView):
    model = Artikel
    template_name = 'blog/detail.html'
    context_object_name = 'artikel'
    slug_field = 'slug'

# CreateView β€” form untuk membuat baru
class ArtikelCreateView(CreateView):
    model = Artikel
    form_class = ArtikelForm
    template_name = 'blog/buat_artikel.html'
    success_url = reverse_lazy('blog:beranda')

    def form_valid(self, form):
        form.instance.penulis = self.request.user
        return super().form_valid(form)

6. Templates: Tampilan HTML

Template adalah file HTML yang dikombinasikan dengan Django Template Language (DTL) untuk menampilkan data secara dinamis. Template memisahkan presentasi dari logika bisnis.

Template Dasar

HTML β€” templates/base.html
<!DOCTYPE html>
<html lang="id">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}Blog{% endblock %} | MyBlog</title>
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
    {% block extra_css %}{% endblock %}
</head>
<body>
    <nav class="navbar">
        <a href="{% url 'blog:beranda' %}">MyBlog</a>
        <ul>
            {% for kategori in kategori_list %}
                <li><a href="{% url 'blog:kategori' kategori.slug %}">{{ kategori.nama }}</a></li>
            {% endfor %}
        </ul>
    </nav>

    <main class="container">
        {% block content %}{% endblock %}
    </main>

    <footer>
        <p>&copy; 2026 MyBlog. Semua hak dilindungi.</p>
    </footer>

    <script src="{% static 'js/app.js' %}"></script>
    {% block extra_js %}{% endblock %}
</body>
</html>

Template Anak (Child Template)

HTML β€” templates/beranda.html
{% extends 'base.html' %}
{% load static %}

{% block title %}{{ judul_halaman }}{% endblock %}

{% block content %}
<h1>{{ judul_halaman }}</h1>

<div class="artikel-grid">
    {% for artikel in artikel_list %}
    <article class="artikel-card">
        {% if artikel.gambar %}
            <img src="{{ artikel.gambar.url }}" alt="{{ artikel.judul }}">
        {% endif %}
        <h2><a href="{{ artikel.get_absolute_url }}">{{ artikel.judul }}</a></h2>
        <p class="meta">
            Oleh {{ artikel.penulis.username }} |
            {{ artikel.created_at|date:"d M Y" }} |
            {{ artikel.kategori.nama }}
        </p>
        <p>{{ artikel.konten|truncatewords:30 }}</p>

        {% if artikel.tags.all %}
        <div class="tags">
            {% for tag in artikel.tags.all %}
                <span class="tag">{{ tag.nama }}</span>
            {% endfor %}
        </div>
        {% endif %}
    </article>
    {% empty %}
    <p>Belum ada artikel yang diterbitkan.</p>
    {% endfor %}
</div>

<!-- Pagination -->
{% if is_paginated %}
<div class="pagination">
    {% if page_obj.has_previous %}
        <a href="?page={{ page_obj.previous_page_number }}">← Sebelumnya</a>
    {% endif %}
    <span>Halaman {{ page_obj.number }} dari {{ page_obj.paginator.num_pages }}</span>
    {% if page_obj.has_next %}
        <a href="?page={{ page_obj.next_page_number }}">Selanjutnya β†’</a>
    {% endif %}
</div>
{% endif %}
{% endblock %}

Template Filters dan Tags

Filter/Tag Fungsi Contoh
{{ var|upper }}Ubah ke huruf besar{{ nama|upper }}
{{ var|date }}Format tanggal{{ tgl|date:"d M Y" }}
{{ var|truncatewords }}Potong teks{{ isi|truncatewords:20 }}
{{ var|default }}Nilai default{{ val|default:"N/A" }}
{% if %}Kondisional{% if user.is_staff %}...{% endif %}
{% for %}Loop{% for item in list %}...{% endfor %}
{% url %}Generate URL{% url 'blog:detail' slug %}
{% csrf_token %}Security tokenDi dalam setiap form POST

7. Django Admin Panel

Salah satu fitur terbaik Django adalah admin panel otomatis yang bisa digunakan untuk mengelola data tanpa perlu membuat UI sendiri. Admin panel sangat berguna untuk CMS, manajemen konten, dan debugging.

Python β€” blog/admin.py
from django.contrib import admin
from .models import Kategori, Artikel, Tag, Komentar

@admin.register(Kategori)
class KategoriAdmin(admin.ModelAdmin):
    list_display = ['nama', 'slug']
    prepopulated_fields = {'slug': ('nama',)}
    search_fields = ['nama']

@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
    list_display = ['nama']
    search_fields = ['nama']

class KomentarInline(admin.TabularInline):
    model = Komentar
    extra = 0
    readonly_fields = ['nama', 'email', 'isi', 'created_at']

@admin.register(Artikel)
class ArtikelAdmin(admin.ModelAdmin):
    list_display = ['judul', 'penulis', 'kategori', 'status', 'created_at']
    list_filter = ['status', 'kategori', 'created_at']
    search_fields = ['judul', 'konten']
    prepopulated_fields = {'slug': ('judul',)}
    raw_id_fields = ['penulis']
    date_hierarchy = 'created_at'
    ordering = ['-created_at']
    inlines = [KomentarInline]

    # Custom actions
    actions = ['publish_artikel', 'draft_artikel']

    def publish_artikel(self, request, queryset):
        queryset.update(status='published')
        self.message_user(request, f'{queryset.count()} artikel diterbitkan.')
    publish_artikel.short_description = "Terbitkan artikel yang dipilih"

    def draft_artikel(self, request, queryset):
        queryset.update(status='draft')
        self.message_user(request, f'{queryset.count()} artikel dijadikan draft.')
    draft_artikel.short_description = "Jadikan draft"

@admin.register(Komentar)
class KomentarAdmin(admin.ModelAdmin):
    list_display = ['nama', 'artikel', 'created_at', 'aktif']
    list_filter = ['aktif', 'created_at']
    search_fields = ['nama', 'email', 'isi']
    list_editable = ['aktif']
πŸ’‘ Tips

Akses admin panel di http://127.0.0.1:8000/admin/ dan login menggunakan superuser yang sudah dibuat. Admin panel bisa dikustomisasi dengan ModelAdmin untuk mengatur tampilan, filter, pencarian, dan aksi massal.

8. Forms: Input Pengguna

Django menyediakan sistem Form yang powerful untuk menangani input pengguna, validasi data, dan rendering HTML form secara otomatis.

Membuat Form

Python β€” blog/forms.py
from django import forms
from .models import Artikel, Komentar

class ArtikelForm(forms.ModelForm):
    class Meta:
        model = Artikel
        fields = ['judul', 'slug', 'kategori', 'konten', 'gambar', 'status', 'tags']
        widgets = {
            'judul': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Judul artikel...'
            }),
            'slug': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'slug-url-artikel'
            }),
            'konten': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 15,
                'placeholder': 'Tulis konten artikel di sini...'
            }),
            'status': forms.Select(attrs={'class': 'form-control'}),
            'tags': forms.CheckboxSelectMultiple(),
        }

    def clean_judul(self):
        judul = self.cleaned_data.get('judul')
        if len(judul) < 10:
            raise forms.ValidationError("Judul minimal 10 karakter!")
        return judul

class KomentarForm(forms.ModelForm):
    class Meta:
        model = Komentar
        fields = ['nama', 'email', 'isi']
        widgets = {
            'nama': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Nama kamu...'
            }),
            'email': forms.EmailInput(attrs={
                'class': 'form-control',
                'placeholder': 'email@kamu.com'
            }),
            'isi': forms.Textarea(attrs={
                'class': 'form-control',
                'rows': 4,
                'placeholder': 'Tulis komentar...'
            }),
        }

Template untuk Form

HTML β€” templates/form.html
{% extends 'base.html' %}

{% block title %}Buat Artikel Baru{% endblock %}

{% block content %}
<h1>Buat Artikel Baru</h1>

<form method="POST" enctype="multipart/form-data">
    {% csrf_token %}

    {% for field in form %}
    <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {{ field }}
        {% if field.help_text %}
            <small class="help-text">{{ field.help_text }}</small>
        {% endif %}
        {% for error in field.errors %}
            <span class="error">{{ error }}</span>
        {% endfor %}
    </div>
    {% endfor %}

    {% if form.non_field_errors %}
    <div class="alert alert-danger">
        {% for error in form.non_field_errors %}
            <p>{{ error }}</p>
        {% endfor %}
    </div>
    {% endif %}

    <button type="submit" class="btn btn-primary">Simpan Artikel</button>
</form>
{% endblock %}

9. Django ORM: Query Database

ORM (Object-Relational Mapping) memungkinkan Anda berinteraksi dengan database menggunakan Python, tanpa perlu menulis SQL. Django ORM mendukung PostgreSQL, MySQL, SQLite, dan Oracle.

Python β€” Django ORM
from blog.models import Artikel, Kategori, Tag
from django.db.models import Count, Q, Avg

# CREATE β€” Membuat data baru
kategori = Kategori.objects.create(nama="Python", slug="python")
artikel = Artikel.objects.create(
    judul="Tutorial Django Pertama",
    slug="tutorial-django-pertama",
    penulis=user,
    kategori=kategori,
    konten="Ini konten artikel...",
    status='published'
)

# READ β€” Membaca data
# Semua data
semua_artikel = Artikel.objects.all()

# Filter berdasarkan kondisi
artikel_python = Artikel.objects.filter(kategori__nama="Python")
artikel_draft = Artikel.objects.filter(status='draft')

# Get satu objek
artikel = Artikel.objects.get(id=1)
artikel = Artikel.objects.get(slug="tutorial-django")

# exclude() β€” kebalikan dari filter
artikel_bukan_draft = Artikel.objects.exclude(status='draft')

# order_by() β€” urutkan
terbaru = Artikel.objects.order_by('-created_at')
terlama = Artikel.objects.order_by('created_at')

# count() β€” hitung
total = Artikel.objects.count()
total_published = Artikel.objects.filter(status='published').count()

# first() dan last()
artikel_pertama = Artikel.objects.first()
artikel_terakhir = Artikel.objects.last()

# exists() β€” cek apakah ada
ada_artikel = Artikel.objects.filter(status='published').exists()

# UPDATE β€” Mengubah data
artikel = Artikel.objects.get(id=1)
artikel.judul = "Judul Baru"
artikel.save()

# Bulk update
Artikel.objects.filter(status='draft').update(status='published')

# DELETE β€” Menghapus data
artikel = Artikel.objects.get(id=1)
artikel.delete()

# Bulk delete
Artikel.objects.filter(status='draft').delete()

Complex Queries

Python β€” Complex ORM
from django.db.models import Count, Q, F, Avg

# Q objects β€” untuk query OR/NOT
artikel = Artikel.objects.filter(
    Q(kategori__nama="Python") | Q(kategori__nama="Django")
)

# Annotasi β€” menambah field kalkulasi
kategori_dengan_jumlah = Kategori.objects.annotate(
    jumlah_artikel=Count('artikel')
).order_by('-jumlah_artikel')

# Related lookups (join)
artikel_dengan_kategori = Artikel.objects.select_related('kategori', 'penulis')
artikel_dengan_tags = Artikel.objects.prefetch_related('tags')

# Aggregasi
total_artikel = Artikel.objects.aggregate(
    total=Count('id'),
    rata_rata_komentar=Avg('komentar__id')
)

# Pagination dari queryset
from django.core.paginator import Paginator

artikel_list = Artikel.objects.filter(status='published')
paginator = Paginator(artikel_list, 10)  # 10 per halaman
page = paginator.get_page(1)  # Halaman pertama

10. URL Routing

URL routing di Django menentukan URL mana yang akan diarahkan ke view function yang mana. URL patterns didefinisikan di file urls.py.

Python β€” blog/urls.py
from django.urls import path
from . import views

app_name = 'blog'  # Namespace URL

urlpatterns = [
    # Beranda
    path('', views.beranda, name='beranda'),

    # Detail artikel berdasarkan slug
    path('artikel/<slug:slug>/', views.detail_artikel, name='detail'),

    # Kategori
    path('kategori/<slug:slug>/', views.kategori_detail, name='kategori'),

    # Buat artikel
    path('baru/', views.buat_artikel, name='buat_artikel'),

    # API endpoints
    path('api/artikel/', views.api_artikel, name='api_artikel'),
]
Python β€” mysite/urls.py (utama)
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls')),
    path('accounts/', include('django.contrib.auth.urls')),
]

# Serve media files in development
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

11. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Django:

Pertanyaan 1: Apa kepanjangan dari MVT dalam konteks Django?

a) Model-View-Template
b) Model-View-Table
c) Module-View-Template
d) Model-Visual-Template

Pertanyaan 2: Perintah apa yang digunakan untuk membuat file migrasi dari perubahan model?

a) python manage.py migrate
b) python manage.py makemigrations
c) python manage.py createsuperuser
d) python manage.py collectstatic

Pertanyaan 3: Apa fungsi dari {% csrf_token %} dalam template Django?

a) Untuk mengenkripsi data form
b) Untuk melindungi form dari serangan CSRF (Cross-Site Request Forgery)
c) Untuk menyimpan data di cookie
d) Untuk mengkompres data form

Pertanyaan 4: Method apa yang digunakan untuk mengambil satu objek atau mengembalikan 404 jika tidak ditemukan?

a) Model.objects.get()
b) Model.objects.filter().first()
c) get_object_or_404()
d) Model.objects.find()

Pertanyaan 5: Apa perbedaan antara ForeignKey dan ManyToManyField?

a) ForeignKey untuk relasi satu-ke-satu, ManyToMany untuk satu-ke-banyak
b) ForeignKey untuk relasi satu-ke-banyak, ManyToMany untuk banyak-ke-banyak
c) Tidak ada perbedaan
d) ForeignKey lebih cepat dari ManyToMany
πŸ” Zoom
100%
🎨 Tema