---
# System prepended metadata

title: 'Belajar Django '
tags: [Book, Templates]

---

# Django
![پایتون چیست؟](https://hackmd.io/_uploads/r1-LyCzPZx.jpg)

## Latar Belakang 

Dokumentasi ini membahas tentang dasar pengembangan web menggunakan framework Django. Materi dimulai dari pemahaman mengenai apa itu framework dalam pengembangan perangkat lunak, kemudian berlanjut ke pengenalan Django sebagai salah satu framework backend berbasis Python. Setelah itu pembahasan akan masuk ke arsitektur Django, kelebihan, serta bagaimana Django mengelola database menggunakan ORM. Dokumentasi ini bertujuan memberikan pemahaman konseptual sebelum masuk ke tahap praktik pengembangan aplikasi.

## Konsep & Landasan Teori
### Apa itu Framework?

![Tambahkan sedikit teks isi (1)](https://hackmd.io/_uploads/BJkauG7vZg.png)

Framework adalah kerangka kerja dalam pengembangan perangkat lunak yang menyediakan struktur, aturan, serta komponen siap pakai untuk membantu developer membangun aplikasi secara lebih cepat, konsisten, dan terorganisir sehingga proses pengembangan menjadi lebih efisien, terstandarisasi, dan mudah dipelihara dalam jangka panjang. Dengan menggunakan framework, developer tidak perlu membuat seluruh sistem dari nol karena banyak fungsi umum sudah disediakan.

Sebagian besar framework web menerapkan konsep arsitektur **Model – View – Controller (MVC)** seperti gambar diatas:

1. **Model** bertugas mengelola data dan berinteraksi dengan database.
2. **View** bertugas menampilkan data ke pengguna dalam bentuk antarmuka.
3. **Controller** berperan sebagai penghubung yang memproses request dari pengguna dan mengatur alur data antara Model dan View.

Dalam pengembangan web, terdapat berbagai framework yang digunakan berdasarkan bahasa pemrograman, seperti **Laravel (PHP)**, **Express.js (JavaScript)**, **Spring Boot (Java)**, dan **Django (Python)**. Meskipun memiliki pendekatan berbeda, semua framework bertujuan untuk mempermudah pembangunan aplikasi yang terstruktur dan scalable.

### Apa itu Django

![Tambahkan sedikit teks isi (2)](https://hackmd.io/_uploads/ByXlOfXPbl.png)

Django adalah web framework berbasis Python yang digunakan untuk membangun aplikasi web secara cepat, aman, dan terstruktur. Django menyediakan fitur bawaan seperti autentikasi pengguna, panel admin otomatis, ORM untuk pengelolaan database, serta routing URL yang sudah terintegrasi.

Keunggulan utama Django terletak pada arsitektur modular berbasis app, di mana satu project dapat dibagi menjadi beberapa aplikasi kecil yang memiliki Model, View, Template, dan URL masing-masing sehingga pengembangan menjadi lebih terorganisir dan scalable seperti contoh gambar diatas, selain itu django juga menggunakan prinsip Don't Repeat Yourself (DRY) untuk mengurangi penulisan kode berulang, serta memiliki sistem keamanan bawaan yang bagus.

### Arsitektur & Alur Django (MVT)
![Tambahkan sedikit teks isi](https://hackmd.io/_uploads/HkLe2MmD-g.png)


1. **URL Configuration (URLConf)**

URLConf bertugas menerima request dari pengguna, misalnya ketika pengguna membuka halaman /about. Django akan mencocokkan URL tersebut dan mengarahkannya ke View yang sesuai.

2. **View**

View berfungsi sebagai pusat logika aplikasi. Setelah menerima request dari URLConf, View akan menentukan proses apa yang harus dilakukan, mengambil atau mengolah data melalui Model, lalu memilih Template yang akan digunakan untuk menampilkan hasilnya.

3. **Model**

Model bertugas mengelola data aplikasi dan berinteraksi langsung dengan database. Model merepresentasikan struktur tabel serta mengatur proses pengambilan, penyimpanan, dan perubahan data. Komunikasi antara View dan Model biasanya dilakukan melalui QuerySet.

4. **Template**

Template bertugas menampilkan data ke pengguna dalam bentuk antarmuka web. Template biasanya berupa file HTML yang menerima data dari View lalu menampilkannya sebagai halaman website.

### Konsep Model, Database, dan Migration di Django
Dalam Django, Model digunakan sebagai representasi struktur database dalam bentuk kode Python. Model ditulis dalam bentuk class yang berisi field-field yang menggambarkan kolom pada tabel database. Dengan pendekatan ini, developer tidak perlu membuat tabel secara manual menggunakan SQL karena Django akan mengubah struktur model menjadi tabel database secara otomatis melalui ORM (Object Relational Mapping).

![Tambahkan sedikit teks isi (3)](https://hackmd.io/_uploads/S1KvCMmwZg.png)

Pada gambar diatas, terlihat bahwa Model berfungsi sebagai penghubung antara aplikasi Django dengan database. Model ditulis dalam bentuk class Python, misalnya berisi field seperti title dan content. Ketika model dibuat, Django akan menerjemahkan struktur tersebut menjadi tabel database yang memiliki kolom sesuai dengan field yang didefinisikan pada model.

Namun, perubahan model tidak langsung mengubah database. Django menggunakan sistem migration untuk mencatat dan menerapkan perubahan struktur database secara terkontrol. Migration dapat dianggap sebagai riwayat perubahan struktur tabel yang tersimpan dalam bentuk file seperti gambar dibawah.


![Tambahkan sedikit teks isi (4)](https://hackmd.io/_uploads/HkbARf7PWx.png)

Pada gambar tersebut, ditunjukkan proses ketika developer melakukan perubahan pada Model. Perubahan tersebut akan dideteksi menggunakan perintah makemigrations, yang berfungsi membuat file migration berdasarkan perubahan model. File migration ini berisi instruksi perubahan struktur database, setelah file migration dibuat, perubahan baru akan diterapkan ke database menggunakan perintah migrate. Proses ini akan membuat, mengubah, atau memperbarui tabel database sesuai dengan struktur Model terbaru.

## Materi Django

### Tools & Dependencies
- Python 3.11.1
Bahasa pemrograman utama 
- Virtual Environment (venv)
Lingkungan terisolasi yang digunakan untuk memisahkan library project.
- Django 4.2
Web framework Python.
- pip
Package manager Python.
- Database (SQLite / PostgreSQL / MySQL)
Tempat penyimpanan data aplikasi.
- Browser
Digunakan untuk mengakses dan menguji aplikasi web yang sedang dikembangkan.
- Code Editor / IDE (VS Code, PyCharm, dll)
Digunakan untuk menulis, mengedit, dan mengelola source code project Django
## Bab 1.Welcome to Try Django 
### Setup Django
1. Install Python
https://www.python.org/downloads/windows/
2. Buat directory baru di windows
```
mkdir Django
```
3. Cek version Python
```
python --version      
Python 3.11.1
```
4. Upgrade pip terlebih dahulu
```
-m pip install -- upgrade 
```
5. cek package di python
```
pip list  

Package    Version
---------- -------
asgiref    3.11.0
pip        26.0
pytz       2025.2
setuptools 65.5.0
sqlparse   0.5.5
tzdata     2025.3
``` 
6. Buat dan aktifkan virtual environment
```
python -m venv Env
Env\scripts\activate.bat
```
7. Install Django didalam virtual environment
```
pip install Django
```
8. Cek apakah Django sudah terinstall atau belum
```
pip list
```
9. Buat project Django 
```
django-admin startproject mywebsite
```
10. masuk ke folder mywebsite dan coba jalankan servernya 
```
cd mywebsite
.\manage.py runserver
```
Contoh hasilnya:
![Screenshot (1493)](https://hackmd.io/_uploads/HJ8ni7XPWg.png)
### Getting started with Django
Ikuti sesuai video tetapi jika teman teman ketika migrate mengalami error yang sama seperti dibawah 
![Screenshot (1509)](https://hackmd.io/_uploads/Hkxj7VEvZl.png)
lakukan hal ini!
1. Buka file settings dan rubah menjadi seperti ini
> muypicky/settings.py
```
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent.parent

```
2. Buka file manage.py dan rubah menjadi seperti ini
> src/manage.py
```
mport os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'muypicky.settings.base')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

```
### What Django Does

#### Django adalah backend web framework
Tugas utamanya:
* Menerima request dari browser
* Mengolah request tersebut
* Mengirim response kembali
* Menyimpan / mengingat data pengguna
* Mengorganisasi aplikasi menggunakan sistem app modular

#### Peran Django Secara Teknis

1. Mengatur URL (Routing) Django menentukan:
URL tertentu → fungsi tertentu
Contoh:
```
/home → tampil halaman home
/products → tampil daftar produk
/profile → tampil profil user
```
Ini disebut:
* URL dispatcher
* Routing system

2. Mengembalikan Response
Setelah menerima request, Django harus mengirim:
* HTML
* JSON
* File
* Text
Contoh:

`return HttpResponse("hello")`

3. Mengingat Data (State & Database)

Contoh:

* Login user
* Riwayat aktivitas
* Data produk
* Data akun

#### Membuat App di Django
```
python manage.py startapp restaurants

```
#### Membuat Page Sederhana
1. sesuaikan ini di urls.py
> muypicky/urls.py
```
from django.contrib import admin
from django.urls import path
from restaurants.views import home

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', home),
]

```
2. Sesuaikan ini di views.py
> restaurants/views.py
```
from django.http import HttpResponse
from django.shortcuts import render

def home(request):
    return HttpResponse("hello")
```
Dan coba jalankan servernya, ketika dibuka akan muncul input hello
#### Penjelasan

## Bab 2.HTML & Django
### Rendering HTML
#### Mencoba HTML di views.py
> restaurants/views.py
```
from django.http import HttpResponse
from django.shortcuts import render

def home(request):
    html_var = 'f strings'
    html_ = f"""<!DOCTYPE html>
    <html lang=en>

    <head>
    </head>
    <body>
    <h1>Hello World!</h1>
    <p>This is {html_var} coming through</p>
    </body>
    </html>
    """
    return HttpResponse(html_)

```
#### Penjelasan
#### Pengiriman HTML Melalui View di Django
Dalam arsitektur Django, view berperan sebagai penghubung antara permintaan pengguna dan respon yang dikirimkan kembali ke browser. Setelah sistem routing mengenali URL yang diakses, Django akan meneruskan permintaan tersebut ke view yang sesuai untuk diproses dan menghasilkan output.

#### Peran HTML dalam Respon Web
Browser tidak menampilkan data secara langsung dari server, melainkan membaca kode HTML yang dikirimkan sebagai respon. HTML merupakan bahasa dasar yang digunakan browser untuk menyusun struktur halaman web seperti teks, heading, paragraf, dan elemen tampilan lainnya. Setiap halaman yang ditampilkan kepada pengguna sebenarnya merupakan hasil interpretasi browser terhadap kode HTML yang diterima.

#### Pengembalian HTML Melalui View
View pada Django dapat mengirimkan respon berupa teks biasa maupun kode HTML. HTML dapat disimpan dalam bentuk string di dalam kode Python dan dikirimkan sebagai respon ke browser. Pendekatan ini menunjukkan bahwa view memiliki kemampuan untuk mengontrol secara langsung isi halaman yang ditampilkan kepada pengguna.

#### Penggunaan String dalam Penyusunan HTML
HTML yang dikirim melalui view merupakan bagian dari string Python. Dalam Python modern, tersedia fitur yang mempermudah pengelolaan string yaitu F-string. F-string memungkinkan penyisipan variabel secara langsung ke dalam string sehingga mempermudah pembuatan konten yang bersifat dinamis.

#### Keterbatasan Penulisan HTML Langsung di View
Meskipun memungkinkan, penulisan HTML secara langsung di dalam view memiliki keterbatasan dalam pengelolaan kode. Struktur HTML yang semakin kompleks dapat membuat view menjadi sulit dibaca, sulit dipelihara, dan kurang efisien dalam pengembangan aplikasi berskala besar.

#### Hubungan Dengan Sistem Template Django
Untuk mengatasi kompleksitas tersebut, Django menyediakan sistem template yang memisahkan logika aplikasi dengan tampilan antarmuka. Dengan menggunakan template, kode HTML ditempatkan dalam file terpisah sehingga view hanya bertugas mengirimkan data yang diperlukan. Pendekatan ini membuat struktur aplikasi lebih terorganisir dan memudahkan pengembangan fitur yang lebih dinamis.

#### Gambaran Konsep Pengiriman Respon Web
Pengiriman HTML melalui view menunjukkan bagaimana Django mengubah permintaan pengguna menjadi tampilan halaman web. Proses ini menegaskan peran view sebagai pengolah logika aplikasi sekaligus pengatur data yang akan ditampilkan pada antarmuka pengguna.
### Render a Django Template
#### Mencoba Membuat Pages Dengan Templates 
1. Mengatur base.py (Settings)
> settings/base.py 
```
BASE_DIR = Path(__file__).resolve().parent.parent.parent 
```
```
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

```
2. Ubah isi file HTML nya
> templates/base.html
```
<!DOCTYPE html>
<html lang=en>

<head>
</head>
<body>
<h1>Hello World!</h1>
<p>
    This is {{ html_var }} coming through
</p>
<p>
Random number is {{ num }}
</p>
</body>
</html>
```
3. Ubah isi Views nya
```
import random
from django.http import HttpResponse
from django.shortcuts import render

def home_old(request):
    html_var = 'f strings'
    num = random.randint(0, 100000000)
    html_ = f"""<!DOCTYPE html>
    <html lang=en>

    <head>
    </head>
    <body>
    <h1>Hello World!</h1>
    <p>This is {html_var} coming through</p>
    <p>This is a random number: {num}</p>
    </body>
    </html>
    """
    return HttpResponse(html_)

def home(request):
    num = random.randint(0, 100000000)
    return render(request, "base.html", {"html_var": True, "num": num})
```
Hasil 
![Screenshot (1512)](https://hackmd.io/_uploads/B1hourNDbx.png)

#### Penjelasan
#### Pengenalan Sistem Template Django
Sistem template Django digunakan untuk memisahkan logika aplikasi dengan tampilan halaman web. Pendekatan ini memungkinkan pengembang mengelola HTML secara terpisah dari kode Python sehingga struktur aplikasi menjadi lebih rapi, mudah dikembangkan, dan lebih terorganisir.

#### Integrasi Template dan Fungsi Render
Template disimpan dalam direktori khusus yang harus didaftarkan dalam konfigurasi proyek agar dapat digunakan oleh Django. Proses menampilkan template dilakukan menggunakan fungsi render yang menghubungkan permintaan pengguna, file template, dan data yang dikirim dari view untuk menghasilkan halaman web.

#### Peran Context dalam Menampilkan Data
Context digunakan untuk mengirimkan data dari view ke template. Data ini memungkinkan halaman web menampilkan informasi dinamis seperti teks, angka, atau hasil pemrosesan program. Template kemudian menampilkan data tersebut menggunakan sintaks variabel bawaan Django.

#### Perbedaan Template Django dan F-String Python
F-string memungkinkan penyisipan variabel langsung ke dalam string Python, sedangkan template Django menyediakan kemampuan tambahan seperti pengolahan logika tampilan dan pengaturan struktur halaman. Template Django lebih fleksibel dan lebih sesuai untuk pengembangan aplikasi web yang kompleks.

#### Alur Rendering Halaman Web
Proses rendering terjadi ketika Django menerima permintaan pengguna, memproses data pada view, menggabungkannya dengan template, lalu menghasilkan HTML yang dikirim ke browser. Pendekatan ini memastikan pemisahan tanggung jawab antara logika aplikasi dan tampilan antarmuka.

### Context in Django Templates
#### Templates + Context
1. Merubah isi views.py agar bisa menggunakan context
> restaurant/views.py
```
import random
from django.http import HttpResponse
from django.shortcuts import render

def home(request):
    num = None
    some_list = [
        random.randint(0, 100000000), 
        random.randint(0, 100000000), 
        random.randint(0, 100000000)
    ]
    condition_bool_item = False
    if condition_bool_item:
        num = random.randint(0, 100000000)
    context = {
        "num": num, 
        "some_list": some_list
    }
    return render(request, "base.html", context)
```
2. Merubah isi base.html agar bisa menggunakan context
> templates/base.html
```
<!DOCTYPE html>
<html lang=en>

<head>
</head>
<body>
<h1>Hello World!</h1>
<p>
    This is <code>{% verbatim %}{{ html_var }}{% endverbatim %}</code> coming through
</p>
<p>
{% if num is not None %}
Random number is {{ num }}
{% endif %}
</p>
<p>
{% for some_item in some_list %}
    {% if some_item|divisibleby:"2" %}
            Even number
    {% endif %}
    
    {{ some_item }}<br/>

{% endfor %}
</p>
<p>Some item is {{ some_item }} </p>

</body>
</html>
```
#### Penjelasan
#### Peran Context dalam Mengontrol Tampilan Template
Context merupakan mekanisme yang memungkinkan view mengirim data ke template. Data ini dapat berupa variabel, nilai boolean, maupun kumpulan data seperti list. Template kemudian menggunakan data tersebut untuk menentukan konten apa yang akan ditampilkan kepada pengguna. Pendekatan ini memungkinkan tampilan halaman berubah secara dinamis tanpa harus mengubah struktur template secara langsung.

#### Penggunaan Conditional Rendering pada Template
Template Django menyediakan kemampuan untuk menampilkan konten berdasarkan kondisi tertentu. Dengan memanfaatkan conditional template tags, template dapat menentukan apakah suatu elemen perlu ditampilkan atau disembunyikan. Conditional ini biasanya memanfaatkan nilai boolean atau keberadaan data tertentu dalam context, sehingga tampilan halaman dapat menyesuaikan kondisi aplikasi secara real-time.

#### Iterasi Data Menggunakan Template Loop
Selain conditional, template Django juga mendukung perulangan data melalui loop. Fitur ini memungkinkan template menampilkan sekumpulan data secara berulang, seperti daftar angka, daftar objek, atau kumpulan informasi lainnya. Variabel yang digunakan dalam loop bersifat lokal dan hanya tersedia selama proses iterasi berlangsung.

#### Template Filters dan Tag Tambahan
Django menyediakan template filters untuk memodifikasi atau mengevaluasi data sebelum ditampilkan. Filter ini dapat digunakan untuk melakukan pengecekan kondisi tertentu, manipulasi nilai, atau transformasi data. Selain itu, Django juga menyediakan tag tambahan seperti verbatim yang memungkinkan template menampilkan kode template mentah tanpa diproses oleh engine Django.

#### Pemisahan Logika antara View dan Template
Praktik terbaik dalam pengembangan Django adalah menempatkan logika utama pada view, sementara template hanya berfungsi sebagai lapisan presentasi. View bertanggung jawab mengolah data, menentukan kondisi, dan menyiapkan context, sedangkan template hanya menampilkan data tersebut. Pendekatan ini membuat kode lebih terstruktur, mudah dipelihara, dan mengurangi kompleksitas pada sisi tampilan.

#### Hubungan dengan Pengembangan Template yang Lebih Lanjut
Pemanfaatan context, conditional, loop, dan filter menjadi dasar dalam membangun template yang dinamis. Konsep ini juga menjadi fondasi untuk fitur lanjutan seperti template inheritance yang memungkinkan pengembang membuat struktur tampilan yang lebih modular dan efisien.

###  Template Inheritance
#### Membuat Lebih Dari 1 Halaman Web
1. Menambah file html untuk about,home,contact, dan sesuaikan base
> templates/home
```
{% extends "base.html" %}

{% block content %}

<h1>Hello World!</h1>
<h3>{{ block.super }}</h3>
<p>
    This is <code>{% verbatim %}{{ html_var }}{% endverbatim %}</code> coming through
</p>
<p>
{% if num is not None %}
Random number is {{ num }}
{% endif %}
</p>
<p>
{% for some_item in some_list %}
    {% if some_item|divisibleby:"2" %}
            Even number
    {% endif %}
    
    {{ some_item }}<br/>

{% endfor %}
</p>
<p>Some item is {{ some_item }} </p>

{% endblock content %}
```
> templates/about
```
{% extends "base.html" %}

{% block head_title %}About || {{ block.super }}{% endblock head_title %}



{% block content %}
<h1>About</h1>
{% endblock  %}
```
> templates/contact
```
{% extends "base.html" %}

{% block head_title %}Contact || {{ block.super }}{% endblock head_title %}


{% block content %}
<h1>Content</h1>
{% endblock  %}
```
> templates/base.html
```
<!DOCTYPE html>
<html lang=en>

<head>
<title>{% block head_title %}naufal.com{% endblock head_title %}</title>
</head>
<body>
<h1>naufal.com</h1>
<a href='/'>Home</a>
<a href='/about/'>About</a>
<a href='/contact/'>Contact</a>

<div class='container'>
{% block content %}{% endblock content %}
</div>

</body>
</html>
```
2. Sesuaikan file urls.py
> muypicky/urls.py
```
from django.contrib import admin
from django.urls import path

from restaurants.views import home, about, contact

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', home),
    path('about/', about),
    path('contact/', contact),
]

```
3. sesuaikan file views.py
> restaurants/views.py
```
import random
from django.http import HttpResponse
from django.shortcuts import render

# Create your views here.
# function based view
def home(request):
    num = None
    some_list = [
        random.randint(0, 100000000), 
        random.randint(0, 100000000), 
        random.randint(0, 100000000)
    ]
    condition_bool_item = False
    if condition_bool_item:
        num = random.randint(0, 100000000)
    context = {
        "num": num, 
        "some_list": some_list
    }
    return render(request, "home.html", context)

def about(request):
    context = {
    }
    return render(request, "about.html", context)


def contact(request):
    context = {
    }
    return render(request, "contact.html", context)
```
hasil
![Screenshot (1515)](https://hackmd.io/_uploads/ByeulIEvZg.png)

#### penjelasan
#### Konsep Dasar Template Inheritance
Template inheritance memungkinkan beberapa halaman menggunakan struktur layout yang sama tanpa harus menulis ulang kode HTML berulang-ulang. Django menyediakan template utama (biasanya disebut base template) yang berisi kerangka halaman seperti doctype, header, navigasi, footer, dan struktur umum lainnya. Halaman lain cukup mewarisi template tersebut dan hanya menambahkan konten yang berbeda.

#### Prinsip DRY (Don’t Repeat Yourself)
Template inheritance dibuat untuk menghindari duplikasi kode. Jika setiap halaman menuliskan ulang elemen seperti navigasi, metadata, atau styling, maka perubahan kecil akan sulit dilakukan karena harus mengedit banyak file. Dengan inheritance, perubahan cukup dilakukan pada template utama dan otomatis diterapkan ke semua halaman yang mewarisinya.

#### Mekanisme Block dan Extends
Django menggunakan extends untuk menghubungkan template turunan dengan template induk. Pada template induk, bagian yang boleh diganti ditandai menggunakan block. Template turunan kemudian mengisi atau mengganti isi block tersebut dengan konten spesifik halaman. Django akan menggabungkan template induk dan turunan saat halaman dirender sehingga menghasilkan HTML lengkap.

#### Fleksibilitas Penggunaan Block
Block tidak hanya digunakan untuk konten utama halaman, tetapi juga dapat dipakai untuk bagian lain seperti judul halaman, metadata, maupun elemen layout tertentu. Django juga menyediakan fitur untuk mempertahankan isi block bawaan sambil menambahkan konten baru, sehingga struktur halaman tetap konsisten tetapi masih bisa dikustomisasi.

#### Dampak pada Struktur Aplikasi Django
Template inheritance membuat pengembangan antarmuka menjadi lebih modular, konsisten, dan mudah dipelihara. Struktur ini juga mempermudah pembuatan navigasi antar halaman serta menjaga keseragaman desain. Konsep ini menjadi fondasi penting dalam pengembangan aplikasi web Django sebelum mengintegrasikan data dinamis dari database atau fitur lanjutan lainnya.

### Include Template Tag
#### Menggunakan Include di Django
1. Buat folder snippets dan isi dengan file css,js,nav,sidebar
> src/templates
```
mkdir snippets
```
> snippets/css.html
```
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
```
> snippets/js.html
```
<script src='https://code.jquery.com/jquery-3.2.1.min.js'></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
```
> snippets/nav.html
```
<div class='container'>
<h1>MuyPicky.com</h1>
<a href='/'>Home</a>
<a href='/about/'>About</a>
<a href='/contact/'>Contact</a>
</div>
```
> snippets/sidebar.html
```
<ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>
```
2. Jangan lupa sesuaikan file htmlnya
> templates/about.html
```
{% extends "base.html" %}

{% block head_title %}About || {{ block.super }}{% endblock head_title %}


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

{% include 'snippets/sidebar.html' %}

{% endblock  %}
```
> templates/base.html
```

<!DOCTYPE html>
<html lang=en>

<head>
<title>{% block head_title %}MuyPicky.com{% endblock head_title %}</title>
{% include 'snippets/css.html' %}
</head>
<body>
{% include 'snippets/nav.html' %}

<div class='container'>
{% block content %}{% endblock content %}
</div>


{% include 'snippets/js.html' %}
</body>
</html>

```
> templates/contact.html
```
{% extends "base.html" %}

{% block head_title %}Contact || {{ block.super }}{% endblock head_title %}


{% block content %}
<h1>Content</h1>
{% include 'snippets/sidebar.html' %}
{% endblock  %}
```
Hasil
![Screenshot (1517)](https://hackmd.io/_uploads/HkXEULVD-g.png)
![Screenshot (1520)](https://hackmd.io/_uploads/HyOwoPNDZg.png)

#### Penjelasan
#### Template Include pada Django
Template include digunakan untuk memecah template besar menjadi bagian-bagian kecil yang lebih modular. Tujuannya menjaga kode tetap rapi, mudah dirawat, dan menghindari pengulangan struktur yang sama di banyak halaman.

#### Fungsi dan Manfaat Include
Include memungkinkan template lain disisipkan ke dalam template utama. Biasanya digunakan untuk elemen yang sering dipakai ulang seperti navigation bar, sidebar, CSS, atau JavaScript. Dengan pendekatan ini, perubahan pada satu file akan otomatis berlaku di semua halaman yang menggunakan bagian tersebut.

#### Struktur dan Organisasi Template
Umumnya dibuat folder khusus seperti snippets untuk menyimpan potongan template kecil. File di dalam folder ini berisi komponen yang bersifat reusable, berbeda dengan template utama yang biasanya digunakan langsung oleh view.

#### Penerapan Include dalam Layout
Template utama dapat memanggil snippet menggunakan tag include. Navigasi biasanya ditempatkan di layout utama agar muncul di semua halaman, sedangkan komponen seperti sidebar bisa dimasukkan hanya pada halaman tertentu. Include juga sering digunakan untuk memisahkan file CSS dan JavaScript agar struktur halaman lebih terorganisir.

#### Konsep Modular dan Efisiensi Pengembangan
Pendekatan include membantu menerapkan prinsip DRY (Don't Repeat Yourself). Template menjadi lebih fleksibel, mudah dikembangkan, dan memudahkan pengelolaan tampilan aplikasi ketika proyek mulai bertambah besar.
###  Class Based Views
#### Mengubah Function Based View menjadi Class Based View di Django
1. Menyesuaikan isi file urls.py
> muypicky/urls.py
```
from django.contrib import admin
from django.urls import path

from restaurants.views import home, about, ContactView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', home),
    path('about/', about),
    path('contact/', ContactView.as_view()),
]

```
2. Menyesuaikan isi file views.py
> restaurants/urls.py
```
import random
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
# Create your views here.
# function based view
def home(request):
    num = None
    some_list = [
        random.randint(0, 100000000), 
        random.randint(0, 100000000), 
        random.randint(0, 100000000)
    ]
    condition_bool_item = False
    if condition_bool_item:
        num = random.randint(0, 100000000)
    context = {
        "num": num, 
        "some_list": some_list
    }
    return render(request, "home.html", context)

def about(request):
    context = {
    }
    return render(request, "about.html", context)


def contact(request):
    context = {
    }
    return render(request, "contact.html", context)

class ContactView(View):
    def get(self, request, *args, **kwargs):
        context = {}
        return render(request, "contact.html", context)
```
3. Menyesuaikan isi file contact.html
> templates/contact.html
```
{% extends "base.html" %}

{% block head_title %}Contact || {{ block.super }}{% endblock head_title %}


{% block content %}
<h1>Content</h1>
{% include 'snippets/sidebar.html' %}
<a href='mailto:youremail@gmail.com'>Email us</a>
{% endblock  %}
```
#### Penjelasan
#### Class-Based Views dalam Django
Class-Based Views (CBV) adalah pendekatan untuk menangani request menggunakan class, bukan fungsi. Pendekatan ini membantu mengurangi pengulangan kode karena banyak halaman sebenarnya melakukan tugas yang mirip, seperti menampilkan template dengan context tertentu.

#### Konsep Dasar Class-Based Views
CBV bekerja dengan mewarisi class bawaan Django, biasanya dari View. Setiap request HTTP ditangani melalui method tertentu, seperti get() untuk menampilkan halaman. Method ini menerima request lalu mengembalikan response, sama seperti function-based view, tetapi dengan struktur yang lebih terorganisir.

#### Cara Kerja dan Integrasi dengan URL
Saat menggunakan CBV, class tidak dipanggil langsung. Django membutuhkan method as_view() untuk mengubah class menjadi callable view yang dapat diproses oleh sistem routing URL. Tanpa pemanggilan ini, view tidak akan berjalan dengan benar.

#### Dukungan HTTP Methods dan Parameter
CBV memungkinkan penanganan berbagai jenis request seperti GET dan POST dalam satu class. Selain itu, view juga dapat menerima parameter dari URL melalui args dan kwargs, sehingga memudahkan pengolahan data dinamis berdasarkan request pengguna.

#### Kelebihan Penggunaan CBV
Pendekatan ini membuat struktur kode lebih modular, scalable, dan mudah dikembangkan. CBV sangat berguna ketika banyak halaman memiliki pola kerja yang serupa atau membutuhkan fitur tambahan seperti validasi, form handling, atau manipulasi data yang lebih kompleks.
### Template View
#### Cara membuat view Django lebih efisien dengan mengganti FBV menjadi Class Based View (CBV) menggunakan TemplateView
1. Ubah isi file urls.py
> muypicky/urls.py
```
from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView

from restaurants.views import HomeView

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', HomeView.as_view()),
    path('about/', TemplateView.as_view(template_name='about.html')),
    path('contact/', TemplateView.as_view(template_name='contact.html')),
]

```
2. Ubah isi file views.py
> restaurants/views.py
```
import random
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView
# Create your views here.

class HomeView(TemplateView):
    template_name = 'home.html'

    def get_context_data(self, *args, **kwargs):
        context = super(HomeView, self).get_context_data(*args, **kwargs)
        num = None
        some_list = [
            random.randint(0, 100000000), 
            random.randint(0, 100000000), 
            random.randint(0, 100000000)
        ]
        condition_bool_item = True
        if condition_bool_item:
            num = random.randint(0, 100000000)
        context = {
            "num": num, 
            "some_list": some_list
        }
        return context
```
#### Penjelasan
#### TemplateView dalam Django

Dalam pengembangan aplikasi Django, terdapat berbagai cara untuk menampilkan halaman web. Salah satu pendekatan yang sering digunakan untuk halaman yang bersifat statis adalah TemplateView, yaitu bagian dari Generic Class Based View yang disediakan langsung oleh Django.

TemplateView berfungsi sebagai mekanisme sederhana untuk menampilkan file template HTML tanpa perlu menuliskan logika render secara manual. Dengan memanfaatkan fitur ini, pengembang dapat membuat struktur kode yang lebih bersih dan mudah dipahami.

#### Peran TemplateView

TemplateView digunakan ketika sebuah halaman hanya membutuhkan tampilan template tanpa logika kompleks. Halaman seperti beranda, tentang, atau kontak biasanya hanya menampilkan informasi statis sehingga sangat cocok menggunakan TemplateView. Penggunaan pendekatan ini membantu menjaga konsistensi struktur kode dan mengurangi penulisan kode yang berulang.

Selain menampilkan template, TemplateView juga tetap memberikan fleksibilitas. Jika suatu saat halaman membutuhkan data tambahan, pengembang dapat menambahkan context data agar template dapat menerima dan menampilkan variabel tertentu.

#### Context Data dalam TemplateView

Context data merupakan data yang dikirim dari view ke template. Dalam TemplateView, data ini dapat digunakan untuk menampilkan informasi dinamis seperti judul halaman, pesan, atau data lain yang ingin ditampilkan pada antarmuka pengguna.

TemplateView menyediakan mekanisme bawaan yang memungkinkan penambahan context data tanpa harus mengubah struktur dasar view. Hal ini membuat pengembangan tetap fleksibel tanpa mengorbankan kesederhanaan.

#### Integrasi Dengan Sistem Routing Django

TemplateView dapat terhubung langsung dengan sistem routing Django. Hal ini memungkinkan halaman statis ditampilkan tanpa perlu membuat view tambahan secara terpisah. Pendekatan ini membantu menjaga konfigurasi aplikasi tetap ringkas dan mudah dipelihara.

Keunggulan Penggunaan TemplateView
* Penggunaan TemplateView memberikan beberapa manfaat utama, antara lain:
* Mengurangi duplikasi kode dalam pembuatan view
* Membuat struktur aplikasi lebih rapi dan terorganisir
* Mempermudah proses pemeliharaan dan pengembangan fitur
* Memberikan fleksibilitas dalam penambahan data ke template
* Memanfaatkan fitur bawaan Django yang mengikuti praktik pengembangan modern

#### Gambaran Umum Penggunaan TemplateView

TemplateView mencerminkan pendekatan Django yang menekankan efisiensi dan keteraturan dalam pengembangan aplikasi web. Dengan memanfaatkan komponen generik yang telah disediakan framework, pengembang dapat lebih fokus pada pengembangan fitur tanpa harus menulis ulang logika dasar yang sebenarnya sudah tersedia.
## Bab 3.Remembering Things
### Remembering things with Models
#### Menyimpan data ke database menggunakan Model dan menampilkannya melalui Admin Django
1. Lakukan Migration Pertama
```
python manage.py migrate
```
2. Buat superuser
```
python manage.py createsuperuser
```
3. Masuk dan isi file models.py
> restaurants/models.py
```
from django.db import models

class RestaurantLocation(models.Model):
    name         = models.CharField(max_length=120)
    location     = models.CharField(max_length=120, null=True, blank=True)
```
4. Tambahkan restaurants di file base.py
> settings/base.py
```
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "restaurants",
]
```
5. Masuk dan isi file admin.py
> restaurants/admin.py
```
from django.contrib import admin
from .models import RestaurantLocation
admin.site.register(RestaurantLocation)
```
6. Lakukan makemigrations dan migrate 
```
python manage.py makemigrations
python manage.py migrate
```
Hasil
![Screenshot (1522)](https://hackmd.io/_uploads/S1gXruEwbg.png)
#### penjelasan
#### Penyimpanan Data dan Model dalam Django
Django tidak hanya digunakan untuk menampilkan halaman web, tetapi juga dirancang untuk menyimpan dan mengelola data. Sistem ini menggunakan database untuk menyimpan informasi sehingga aplikasi dapat “mengingat” data, seperti pengguna, artikel, atau daftar objek tertentu.

#### Peran Database dan Django Admin
Django menyediakan sistem backend bawaan melalui Django Admin. Fitur ini memungkinkan pengembang melihat, menambah, dan mengelola data secara langsung melalui antarmuka web. Data yang disimpan oleh admin berasal dari database yang dibuat secara otomatis ketika menjalankan proses migrasi.

Database ini terhubung dengan aplikasi bawaan Django seperti autentikasi pengguna. Informasi seperti username, email, dan data login disimpan dalam model yang telah disediakan oleh framework.

#### Model sebagai Representasi Data

Model adalah komponen yang mendefinisikan struktur data dalam Django. Model digunakan untuk menentukan atribut data yang akan

### More on Model Fields
#### Menambah Field Baru
1. Masuk ke file models.py
> restaurants/models.py
```
from django.db import models

class RestaurantLocation(models.Model):
    name            = models.CharField(max_length=120)
    location        = models.CharField(max_length=120, null=True, blank=True)
    category        = models.CharField(max_length=120, null=True, blank=True)
    timestamp       = models.DateTimeField(auto_now_add=True)
    updated         = models.DateTimeField(auto_now=True)
    #my_date_field   = models.DateField(auto_now=False, auto_now_add=False)
```
2. Lakukan makemigrations & migrate
> Pilihan 1 Django akan meminta kamu isi nilai sementara.
> Pilihan 2 Kamu bisa back/quit dan mengatur default untuk isi tabelnya.
```
python manage.py makemigrations
python manage.py migrate
```
Hasil
![image](https://hackmd.io/_uploads/S1LLtdNw-l.png)
#### Penjelasan
#### Penambahan Field pada Model Django
Model dalam Django dapat dikembangkan dengan menambahkan field baru untuk menyimpan informasi tambahan. Setiap field merepresentasikan kolom dalam database. Contohnya, penambahan field kategori memungkinkan penyimpanan jenis data tertentu seperti klasifikasi restoran.

Setiap field memiliki konfigurasi penting seperti batas panjang karakter serta pengaturan apakah data boleh kosong. Konfigurasi ini mengontrol validasi data baik pada tingkat database maupun pada form Django.

#### Pengaruh Konfigurasi Field terhadap Validasi Data
Beberapa parameter memiliki peran khusus dalam pengelolaan data. Batas panjang karakter menentukan jumlah maksimal karakter yang dapat disimpan. Pengaturan yang mengizinkan nilai kosong pada database memungkinkan data tidak wajib diisi, sedangkan pengaturan kosong pada form menentukan apakah pengguna harus mengisi field tersebut pada antarmuka admin atau form aplikasi.

Perubahan konfigurasi field akan langsung memengaruhi perilaku validasi serta tampilan form pada Django Admin.

#### Proses Sinkronisasi Model dengan Database
Setiap perubahan pada model harus disinkronkan dengan database melalui sistem migrasi Django. Proses ini memastikan struktur database selalu sesuai dengan definisi model terbaru. Migrasi berfungsi untuk menyiapkan perubahan struktur data serta menerapkannya ke database sehingga data dapat disimpan dengan benar.

#### Jenis Field dan Fleksibilitas Penyimpanan Data
Django menyediakan berbagai tipe field seperti teks, angka, tanggal, dan waktu. Field tanggal dan waktu sering digunakan untuk mencatat kapan data dibuat atau diperbarui secara otomatis. Fitur ini membantu pelacakan perubahan data dan mendukung pengelolaan informasi secara historis.

Selain field otomatis, pengembang juga dapat membuat field manual untuk menyimpan informasi waktu tertentu sesuai kebutuhan aplikasi.

#### Pentingnya Eksperimen dalam Pengembangan Model

Pengembangan model bersifat fleksibel dan memungkinkan eksplorasi berbagai tipe field. Eksperimen menjadi bagian penting dalam memahami bagaimana data disimpan dan dikelola dalam Django. Kesalahan konfigurasi dapat diperbaiki melalui perubahan model dan migrasi ulang sehingga proses pembelajaran tetap aman dilakukan.
### Displaying Saved Data
#### menampilkan database ke halaman web
1. Buat folder templates di restaurants dan isi dengan file restaurants_list.html
> restaurants/templates
```
{% extends "base.html" %}

{% block head_title %}Restaurants | {{ block.super}}{% endblock head_title %}

{% block content %}
<h1>Restaurant List</h1>

<ul>
{% for obj in object_list %}
    <li>{{ obj }} <br/>
    {{ obj.name }} {{ obj.location }} {{ obj.category }} {{ obj.timestamp }} {{ obj.updated }}</li>
{% endfor %}
</ul>
{% endblock %}
```
2. Ubah urls.py
> muypicky/urls.py
```
from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView

from restaurants.views import restaurant_listview

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', TemplateView.as_view(template_name='home.html'), name='home'),
    path('restaurants/', restaurant_listview, name='restaurant-list'),
    path('about/', TemplateView.as_view(template_name='about.html'), name='about'),
    path('contact/', TemplateView.as_view(template_name='contact.html'), name='contact'),
]
```
3. Ubah models.py
> restaurants/models.py
```
from django.db import models
class RestaurantLocation(models.Model):
    name            = models.CharField(max_length=120)
    location        = models.CharField(max_length=120, null=True, blank=True)
    category        = models.CharField(max_length=120, null=True, blank=True)
    timestamp       = models.DateTimeField(auto_now_add=True)
    updated         = models.DateTimeField(auto_now=True)
    #my_date_field   = models.DateField(auto_now=False, auto_now_add=False)
    def __str__(self):
        return self.name
```
4.Ubah views.py
> restaurants/views.py
```
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
from django.views.generic import TemplateView

from .models import RestaurantLocation

def restaurant_listview(request):
    template_name = 'restaurants/restaurants_list.html'
    queryset = RestaurantLocation.objects.all()
    context = {
        "object_list": queryset
    }
    return render(request, template_name, context)
```
Hasil 
![image](https://hackmd.io/_uploads/rkyt7FNwbg.png)
![image](https://hackmd.io/_uploads/rJZ9QtVvbl.png)
#### Penjelasan
#### Function-Based View untuk Daftar Restoran

Langkah-langkah:
* Buat fungsi view, misalnya restaurant_list_view, yang menerima request.
* Gunakan render() untuk menghubungkan view dengan template HTML.
* Siapkan context yang berisi data yang akan ditampilkan.
* Ambil data dari database menggunakan model:

```
from .models import Restaurant
object_list = Restaurant.objects.all()
context = {"object_list": object_list}
```
* Di template, iterasi data menggunakan loop
```
<ul>
  {% for object in object_list %}
    <li>{{ object.name }} - {{ object.location }} - {{ object.category }}</li>
  {% endfor %}
</ul>
```
Dengan cara ini, semua restoran yang tersimpan di database akan ditampilkan secara otomatis.

#### Kustomisasi Nama Objek

Secara default, Django menampilkan nama model sebagai representasi string objek (Restaurant object).

* Untuk menampilkan nama yang lebih user-friendly, kita bisa menambahkan __str__() method pada model:

```
class Restaurant(models.Model):
    name = models.CharField(max_length=120)
    location = models.CharField(max_length=120, null=True, blank=True)
    category = models.CharField(max_length=120, null=True, blank=True)

    def __str__(self):
        return f"{self.name} - {self.location}"
```
* Dengan ini, tampilan di admin dan template menjadi lebih informatif.

### Understanding QuerySets
#### Pengertian QuerySet dalam Django

QuerySet adalah cara Django mengambil data dari database. Hasilnya berupa kumpulan objek (mirip list Python) yang merepresentasikan baris data di tabel database. Hampir semua interaksi data di Django—baik di views, templates, maupun shell—menggunakan QuerySet.

#### Menggunakan QuerySet di Django Shell
Django menyediakan python shell khusus untuk bereksperimen dengan data secara cepat.

Contoh penerapan:

`python manage.py shell`

Di dalam shell:

```
from restaurants.models import RestaurantLocation
qs = RestaurantLocation.objects.all()
```
Artinya:
* objects.all() → mengambil semua data restoran
* qs sekarang berisi QuerySet
```
for obj in qs:
    print(obj.name)
```
Ini sama seperti yang dilakukan di template {% for object in object_list %}.

#### Filter dan Pencarian Data
QuerySet bisa difilter agar hanya mengambil data tertentu.

Contoh penerapan:
`qs = RestaurantLocation.objects.filter(category__iexact="Mexican")`
Penjelasan:

* filter() → menyaring data
* __iexact → pencarian tidak sensitif huruf besar/kecil

Cek jumlah data:
`qs.count()`
Lebih efisien daripada len(qs) untuk data besar.

#### Update Data dengan QuerySet
QuerySet dapat mengubah banyak data sekaligus.
Contoh:
```
qs.update(category="American")
```
Artinya:
* Semua data dalam QuerySet akan diubah
* Django mengembalikan jumlah objek yang ter-update
Setelah itu, filter lama (misalnya Mexican) bisa jadi kosong karena datanya sudah berubah.
#### Membuat Data Baru (Best Practice)
Ada dua cara membuat data, tapi yang direkomendasikan adalah objects.create().

Contoh penerapan:
```
RestaurantLocation.objects.create(
    name="Kronick Tacos",
    location="Corona Del Mar",
    category="Mexican"
)
```
Keunggulan:
* Data langsung tersimpan ke database
* timestamp dan field otomatis langsung terisi
Berbeda dengan cara manual (obj = Model() lalu save()), metode ini lebih ringkas dan aman.

#### Fungsi Tambahan QuerySet yang Penting

Beberapa contoh penggunaan lanjutan:

```
qs.exists()        # cek apakah data ada
qs.exclude(name__icontains="Taco")  # kecuali yang mengandung kata tertentu
```
Semua ini tetap menghasilkan QuerySet, sehingga bisa dikombinasikan satu sama lain.
#### Generic List View
ListView adalah Class-Based View yang otomatis:
* mengambil QuerySet
* mengirimkannya ke template
* menangani list data tanpa harus render() manual

Contoh dasar:
```

from django.views.generic import ListView
from .models import RestaurantLocation

class RestaurantListView(ListView):
    model = RestaurantLocation
```
Tanpa apa pun lagi, Django sudah otomatis:
* QuerySet: RestaurantLocation.objects.all()
* Template: restaurants/restaurantlocation_list.html
* Context: object_list

#### ListView dengan Filter Statis
Kalau ingin list khusus kategori tertentu, gunakan queryset.
Contoh:
```
class MexicanRestaurantListView(ListView):
    queryset = RestaurantLocation.objects.filter(
        category__iexact="Mexican"
    )
```
Penerapan URL:
```
path("mexican/", MexicanRestaurantListView.as_view())
```
Hasil:

/restaurants/mexican/ → hanya restoran Mexican


#### ListView Dinamis dengan Slug (Search)
Supaya satu ListView bisa dipakai untuk banyak kategori, gunakan parameter URL + get_queryset().

URL:
```
path("search/<slug:slug>/", RestaurantListView.as_view())
```
View:
```
class RestaurantListView(ListView):
    model = RestaurantLocation

    def get_queryset(self):
        slug = self.kwargs.get("slug")
        if slug:
            return RestaurantLocation.objects.filter(
                category__icontains=slug
            )
        return RestaurantLocation.objects.all()

```

Contoh akses:

* /search/mexican/
* 
* /search/asian/
* 
* /search/fusion/

#### Filter Lebih Fleksibel dengan Q Object

Kalau ingin lebih dari satu kondisi (OR / AND), gunakan Q.
```
from django.db.models import Q

class RestaurantListView(ListView):
    model = RestaurantLocation

    def get_queryset(self):
        slug = self.kwargs.get("slug")
        if slug:
            return RestaurantLocation.objects.filter(
                Q(category__iexact=slug) |
                Q(category__icontains=slug)
            )
        return RestaurantLocation.objects.all()
```
Artinya:

* cocokkan exact
* atau mengandung kata
* tetap satu QuerySet

#### Template Otomatis ListView

Kalau tidak set template_name, Django otomatis pakai:

`<app>/<model>_list.html`

Untuk model RestaurantLocation:

`restaurants/restaurantlocation_list.html`
Di template:
```
<ul>
{% for obj in object_list %}
    <li>{{ obj.name }} - {{ obj.category }}</li>
{% endfor %}
</ul>
```
#### Restaurant Profile Detail
#### mengubah cara web mengambil & menampilkan data sehinngga yang tadinya statis jadi dinamis
1. Membuat file restaurantslocation_detail.html baru didalam template/restaurants dan mengganti nama file html sebelumnya menjadi restaurantslocation_list.html
> templates/restaurants
```
{% extends "base.html" %}

{% block head_title %}Restaurants | {{ block.super}}{% endblock head_title %}

{% block content %}
<h1>{{ object.name }} <small> {{ object.category }}</small></h1>
<p>{{ object.location }}</p>
<p>{{ object.timestamp }}, Updated {{ object.updated|timesince }} ago</p>
{% endblock %}
```
2. Merubah isi views.py
> retaurants/views.py
```
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.views import View
from django.views.generic import TemplateView, ListView, DetailView

from .models import RestaurantLocation

def restaurant_listview(request,):
    template_name = 'restaurants/restaurants_list.html'
    queryset = RestaurantLocation.objects.all()
    context = {
        "object_list": queryset
    }
    return render(request, template_name, context)


class RestaurantListView(ListView):
    def get_queryset(self):
        slug = self.kwargs.get("slug")
        if slug:
            queryset = RestaurantLocation.objects.filter(
                    Q(category__iexact=slug) |
                    Q(category__icontains=slug)
                )
        else:
            queryset = RestaurantLocation.objects.all()
        return queryset


class RestaurantDetailView(DetailView):
    queryset = RestaurantLocation.objects.all()
    
    def get_object(self, *args, **kwargs):
        rest_id = self.kwargs.get('rest_id')
        obj = get_object_or_404(RestaurantLocation, id=rest_id) # pk = rest_id
        return obj
```
3.Merubah isi urls.py
```
from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView

from restaurants.views import (
    RestaurantListView,
    RestaurantDetailView,
)

urlpatterns = [
    path("admin/", admin.site.urls),

    path("", TemplateView.as_view(template_name="home.html"), name="home"),

    path("restaurants/", RestaurantListView.as_view(), name="restaurant-list"),

    path(
        "restaurants/<int:rest_id>/",
        RestaurantDetailView.as_view(),
        name="restaurant-detail",
    ),

    path("about/", TemplateView.as_view(template_name="about.html"), name="about"),

    path("contact/", TemplateView.as_view(template_name="contact.html"), name="contact"),
]
```
#### Penjelasan
#### Konsep DetailView
DetailView merupakan generic view Django yang digunakan untuk menampilkan satu data spesifik dari database. Data tersebut diambil berdasarkan primary key (PK) atau slug yang dikirim melalui URL. Setiap model Django secara otomatis memiliki primary key sebagai identitas unik setiap objek.

#### Hubungan URL dengan Data
#### Penggunaan DetailView dan Primary Key

Django menyediakan DetailView sebagai generic view untuk menampilkan satu objek model. Objek tersebut diambil berdasarkan primary key (PK) yang dikirim melalui URL. Setiap model Django secara otomatis memiliki PK yang juga dikenal sebagai id, sehingga tidak perlu didefinisikan secara manual.

#### Integrasi URL dengan DetailView

Parameter PK pada URL berfungsi sebagai penghubung antara permintaan pengguna dan data di database. Django akan menggunakan nilai PK tersebut untuk mencari objek yang sesuai. Jika objek tidak ditemukan, sistem akan secara otomatis menghasilkan error 404, sehingga aplikasi tetap aman.

#### Context Default pada Template

DetailView menyediakan context bawaan bernama object yang merepresentasikan satu instance model. Context ini dapat langsung digunakan di template untuk menampilkan atribut model seperti nama restoran, kategori, lokasi, serta data waktu menggunakan template filter bawaan Django.

#### Penyesuaian Pengambilan Objek

Jika nama parameter URL diubah dari pk, maka proses pengambilan objek harus disesuaikan. Django memungkinkan pengembang untuk menimpa metode pengambilan objek agar tetap dapat menemukan data berdasarkan parameter yang diinginkan. Fleksibilitas ini mendukung pengembangan URL yang lebih deskriptif dan terstruktur.
### SlugField & Unique Slug Generator
#### Mengganti ID menjadi Slug di URL
1. Menambah file utils.py di folder restaurants
> restaurants/utils.py
```
import random
import string

from django.utils.text import slugify
'''
random_string_generator is located here:
http://joincfe.com/blog/random-string-generator-in-python/
'''

def random_string_generator(size=10, chars=string.ascii_lowercase + string.digits):
    return ''.join(random.choice(chars) for _ in range(size))


def unique_slug_generator(instance, new_slug=None):
    """
    This is for a Django project and it assumes your instance 
    has a model with a slug field and a title character (char) field.
    """
    if new_slug is not None:
        slug = new_slug
    else:
        slug = slugify(instance.title)

    Klass = instance.__class__
    qs_exists = Klass.objects.filter(slug=slug).exists()
    if qs_exists:
        new_slug = "{slug}-{randstr}".format(
                    slug=slug,
                    randstr=random_string_generator(size=4)
                )
        return unique_slug_generator(instance, new_slug=new_slug)
    return slug
```
2. Menyesuaikan file restaurantslocation_details.html
```
{% extends "base.html" %}

{% block head_title %}Restaurants | {{ block.super}}{% endblock head_title %}

{% block content %}
<h1>{{ object.title }} <small> {{ object.category }}</small></h1>
<p>{{ object.location }}</p>
<p>{{ object.timestamp }}, Updated {{ object.updated|timesince }} ago</p>
{% endblock %}
```
3. merubah isi file models.py
```
from django.db import models
class RestaurantLocation(models.Model):
    name            = models.CharField(max_length=120)
    location        = models.CharField(max_length=120, null=True, blank=True)
    category        = models.CharField(max_length=120, null=True, blank=True)
    timestamp       = models.DateTimeField(auto_now_add=True)
    updated         = models.DateTimeField(auto_now=True)
    slug            = models.SlugField(null=True, blank=True)
    #my_date_field   = models.DateField(auto_now=False, auto_now_add=False)
    def __str__(self):
        return self.name

    @property
    def title(self):
        return self.name
```
#### Penjelasan
#### Penggunaan Slug untuk URL yang Lebih Deskriptif
Dalam perancangan URL, keterbacaan sangat penting. URL berbasis angka memang berfungsi, tetapi kurang informatif. Dengan menggunakan slug, URL menjadi lebih deskriptif dan mudah dipahami oleh manusia, misalnya nama restoran langsung terlihat pada alamat halaman.

#### Penambahan Field Slug pada Model
Slug disimpan sebagai field khusus di dalam model menggunakan SlugField. Field ini berfungsi sebagai pengenal unik selain primary key. Agar fleksibel saat pengembangan, slug dapat diatur agar memperbolehkan nilai kosong sementara, terutama jika field ditambahkan setelah data sudah ada di database.

#### Pembuatan Unique Slug Generator
Slug yang dihasilkan harus bersifat unik. Django menyediakan fungsi slugify untuk mengubah teks menjadi format slug, namun tidak menjamin keunikan. Oleh karena itu dibuat utility function yang:
* Mengambil instance model
* Menghasilkan slug dari nama objek
* Mengecek ke database apakah slug sudah digunakan
* Menambahkan string acak jika diperlukan agar tetap unik

#### Penggunaan Property untuk Konsistensi Atribut
Agar utility slug generator dapat digunakan secara konsisten, ditambahkan property pada model yang mengembalikan nama restoran sebagai title. Pendekatan ini membuat kode lebih rapi dan fleksibel tanpa mengubah struktur data asli.
### Signal for Unique Slug
#### Perubahan pada Model
File: `restaurants/models.py`
Tujuan tahap ini adalah menambahkan slug sebagai pengenal URL yang lebih deskriptif dibanding ID.

Yang diubah:
* Menambahkan field slug
* Menambahkan property title agar konsisten dengan slug generator
```

from django.db import models

class RestaurantLocation(models.Model):
    name = models.CharField(max_length=120)
    location = models.CharField(max_length=120, blank=True, null=True)
    category = models.CharField(max_length=120, blank=True, null=True)
    slug = models.SlugField(blank=True, null=True)

    @property
    def title(self):
        return self.name
```


Apa yang terjadi:

* Model sekarang memiliki kolom slug
* title digunakan oleh slug generator tanpa mengubah struktur data asli
* 

#### Membuat Unique Slug Generator
File: `restaurants/utils.py`
Tujuan tahap ini adalah menghasilkan slug yang unik secara otomatis.

Yang ditambahkan:
* fungsi untuk membuat slug
* Mengecek ke database apakah slug sudah digunakan

```
import random
import string
from django.utils.text import slugify

def random_string_generator(size=4, chars=string.ascii_lowercase + string.digits):
return ''.join(random.choice(chars) for _ in range(size))

def unique_slug_generator(instance):
slug = slugify(instance.title)
Klass = instance.__class__
qs = Klass.objects.filter(slug=slug).exists()
if qs:
slug = f"{slug}-{random_string_generator()}"
return slug
```

Apa yang terjadi:
* Nama restoran diubah menjadi format URL-friendly
* Jika slug sudah ada, ditambahkan string acak agar tetap unik

#### Menambahkan Signal pre_save
File: `restaurants/models.py`
Tujuan tahap ini adalah mengisi slug secara otomatis sebelum data disimpan.
Yang diubah:

* Import signal
* Membuat receiver pre_save
* Menghubungkannya ke model

```
from django.db.models.signals import pre_save
from django.dispatch import receiver
from .utils import unique_slug_generator

@receiver(pre_save, sender=RestaurantLocation)
def restaurant_pre_save_receiver(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = unique_slug_generator(instance)
```
Setiap kali data akan disimpan:
* Django mengecek apakah slug kosong
* Jika kosong, slug otomatis dibuat
* Tidak perlu memanggil save() lagi

## Bab 4.Forms,Views,Model,and More
### Slugs as URL Params
#### Tujuan Penggunaan Slug pada Aplikasi
Pembuatan slug bertujuan untuk meningkatkan kualitas URL agar lebih deskriptif dan mudah dibaca. URL berbasis slug memungkinkan pengguna dan mesin pencari memahami isi halaman hanya dari alamat URL, misalnya nama restoran langsung terlihat tanpa harus mengandalkan ID numerik.

Slug membuat struktur navigasi aplikasi lebih ramah pengguna dan lebih mudah dikembangkan di masa depan.

#### Perubahan Pola URL untuk Menggunakan Slug
File yang diubah
`urls.py`
Perubahan kode
`path('restaurants/<slug:slug>/', RestaurantDetailView.as_view())`

#### Fungsi perubahan
URL detail restoran kini menerima parameter slug sebagai identifier utama, menggantikan penggunaan primary key. Django secara otomatis menangkap nilai slug dari URL dan meneruskannya ke view.

#### Alasan perubahan
* URL menjadi lebih informatif
* Tidak bergantung pada ID database
* Lebih fleksibel untuk SEO dan navigasi 

#### Dampak ke aplikasi

Setiap halaman detail restoran sekarang diakses melalui slug unik, bukan angka.

#### Penyesuaian DetailView untuk Lookup Berdasarkan Slug

File yang diubah
`views.py`
Kode terkait
```
class RestaurantDetailView(DetailView):
    queryset = RestaurantLocation.objects.all()
```
#### Fungsi kode
DetailView secara otomatis akan:
* Mencari objek berdasarkan parameter URL
* Menggunakan field slug karena nama parameter URL adalah slug
* Mengirimkan objek ke template dengan context bernama object
#### Alasan tidak perlu override get_object
Django Generic DetailView sudah mendukung pencarian berdasarkan slug secara default jika:
* URL mengirimkan parameter bernama slug
* Model memiliki field slug
Ini membuat kode lebih bersih dan sesuai praktik Django modern.
#### Penambahan Link Dinamis pada List View
File yang diubah
`restaurantslocation_list.html`
Perubahan kode
```
<li>
  <a href="/restaurants/{{ obj.slug }}/">{{ obj }}</a><br/>
  {{ obj.name }} {{ obj.location }} {{ obj.category }} {{ obj.timestamp }} {{ obj.updated }}
</li>
```
Fungsi kode
* Membuat link ke halaman detail restoran
* Menggunakan slug sebagai bagian URL
* Setiap item list memiliki URL unik sesuai slug-nya
Dan tanpa link berbasis slug, pengguna tidak dapat mengakses halaman detail secara langsung dari daftar restoran.
### Get Single Items from the DB

Setelah memahami slug dan DetailView, langkah berikutnya adalah memahami bagaimana Django mengambil satu data spesifik dari database. Ini penting karena hampir semua halaman detail, edit, atau delete bergantung pada proses lookup satu object.

#### Pengambilan Data Menggunakan QuerySet
**Konsep yang dibahas**
QuerySet menghasilkan kumpulan data, bukan satu object tunggal.
Contoh:
```
RestaurantLocation.objects.all()
RestaurantLocation.objects.filter(category__icontains="mexican")
```
Cara mengambil satu item dari QuerySet

```
qs = RestaurantLocation.objects.filter(category__icontains="mexican")
qs.first()
qs.last()
```

Fungsi pendekatan ini
* Aman dari error
* Tidak melempar exception jika data kosong

Keterbatasan
* Tidak menjamin object tertentu
* Tidak cocok untuk URL detail
* Kurang eksplisit secara logika

#### Pengambilan Data Menggunakan .get()
Kode yang dibahas

```
obj = RestaurantLocation.objects.get(pk=1)
obj = RestaurantLocation.objects.get(slug=slug)
```
Fungsi `.get()`
* Mengambil satu object spesifik
* Digunakan ketika kita yakin data tersebut ada

Risiko penggunaan `.get()`
Jika data tidak ditemukan:
`RestaurantLocation.DoesNotExist`
Ini akan menyebabkan 500 Internal Server Error jika tidak ditangani.

#### Penanganan Error dengan get_object_or_404
**File yang diubah**
```
restaurants/views.py
```
Perubahan kode
```
from django.shortcuts import get_object_or_404

obj = get_object_or_404(RestaurantLocation, slug=slug)
```
Fungsi
* Mengambil object jika ada
* Mengembalikan HTTP 404 jika tidak ditemukan

DetailView sudah menggunakan mekanisme ini secara otomatis, sehingga kita jarang perlu menulisnya sendiri jika memakai Generic View.

#### Perbandingan Function-Based View dan Class-Based View
Function-Based Detail View
```
def restaurant_detailview(request, slug):
    obj = RestaurantLocation.objects.get(slug=slug)
```

Kelemahan
* Rentan error jika data tidak ada
* Harus menangani exception sendiri
* Kurang reusable
Class-Based Detail View
```
class RestaurantDetailView(DetailView):
    queryset = RestaurantLocation.objects.all()
```
Keunggulan
* Lookup otomatis
* Penanganan 404 bawaan
* Context object otomatis tersedia
* Lebih bersih dan konsisten

#### Pengaruh Filter pada queryset DetailView

Kode yang dibahas
```
class RestaurantDetailView(DetailView):
    queryset = RestaurantLocation.objects.filter(category__iexact='asian')
```
**Fungsi filter ini**
DetailView hanya akan mencari object di dalam queryset tersebut.
**Dampak**
* Slug valid tetap menghasilkan 404 jika tidak memenuhi filter
Berguna untuk:
* Filter berdasarkan user
* Hak akses
* Data ownership

#### Alternatif Aman Menggunakan QuerySet + Exists

Kode yang dibahas
```
qs = RestaurantLocation.objects.filter(slug=slug)
if qs.exists():
    obj = qs.first()
```
Fungsi
* Tidak melempar exception
* Bisa dikombinasikan dengan logika tambahan

Kapan digunakan
* Validasi kompleks
* Kondisi bercabang
* Query dinamis

Perbedaan Field dan Property pada Query

Property yang dibahas
```
@property
def title(self):
    return self.name
```
Kenapa tidak bisa dipakai di query

`RestaurantLocation.objects.get(title="ABC")  # ERROR`
### Saving Data the Hard + Wrong Way

#### Pembuatan Form Manual (Long Way)
File yang ditambahkan
`restaurants/forms.py`
Kode yang ditambahkan

from django import forms
```
class RestaurantCreateForm(forms.Form):
    name = forms.CharField()
    location = forms.CharField(required=False)
    category = forms.CharField(required=False)
```
Fungsi kode
* Mendefinisikan struktur data input
* Menentukan field wajib dan opsional
* Belum digunakan untuk validasi (akan di video berikutnya)

#### Pembuatan Template Form HTML

File yang ditambahkan
`templates/restaurants/form.html`
Kode utama
```
<form method='POST'> {% csrf_token %}
    <input type='text' name='title' placeholder="Your Title"><br/>
    <input type='text' name='location' placeholder="Location"><br/>
    <input type='text' name='category' placeholder="Category"><br/>
    <button type='submit'>Save</button>
</form>
```
Fungsi tiap bagian
* method='POST' → data dikirim ke server secara aman
* {% csrf_token %} → proteksi keamanan Django
* name="" → key yang dipakai di request.POST
Tanpa csrf_token, Django akan menolak request POST.

#### Perbedaan GET dan POST pada Form

**GET (Default)**
* Data muncul di UR
* Tidak aman untuk menyimpan data
* Cocok untuk pencarian
**POST (Digunakan di sini)**
* Data dikirim di body request
* Tidak terlihat di URL
* Digunakan untuk CREATE / UPDATE / DELETE
Itulah alasan form wajib menggunakan POST saat menyimpan ke database.

**Penambahan URL Create**
File yang diubah
`urls.py`
Kode yang ditambahkan
```
url('restaurants/create/', restaurant_createview),
```
Tujuan
* Membuat URL khusus /restaurants/create/
* Menghindari konflik dengan slug detail
Kenapa penting:
Slug seperti /restaurants/create/ bisa bentrok jika ada restoran bernama create.

#### Pengamanan Slug dari Konflik URL
File yang diubah
`utils.py`
Kode penting
```
DONT_USE = ['create']
```
```
if slug in DONT_USE:
    new_slug = f"{slug}-{random_string_generator(size=4)}"
```
Fungsi
* Mencegah slug yang bentrok dengan URL sistem
* Menjamin slug tetap unik dan aman

Contoh hasil:
* create → create-a9f3

#### Pembuatan Create View (Function-Based View)
File yang diubah

`views.py`

Kode utama
```
def restaurant_createview(request):
    if request.method == "POST":
        title = request.POST.get("title")
        location = request.POST.get("location")
        category = request.POST.get("category")

        obj = RestaurantLocation.objects.create(
            name=title,
            location=location,
            category=category
        )
        return HttpResponseRedirect("/restaurants/")

    return render(request, "restaurants/form.html", {})
```

Alur kerja view
1. Cek apakah request POST
2. Ambil data dari request.POST
3. Simpan ke database
4. Redirect ke halaman list

#### CSRF Token dan Keamanan

**Apa yang terjadi tanpa CSRF**

Django menolak request
Error: Forbidden (403)

Cara Django bekerja
`<input type="hidden" name="csrfmiddlewaretoken" value="...">`
Token ini:
* Dihasilkan otomatis
* Diverifikasi setiap POST
* Mencegah request palsu dari luar situs
### The Power of Django Forms
Pada video sebelumnya, data diambil langsung dari request.POST dan langsung disimpan ke database.
Sekarang pendekatan tersebut digantikan dengan Django Form agar:
* Data tervalidasi sebelum masuk database
* Struktur input konsisten
* Keamanan dan keterbacaan kode meningkat

#### Instansiasi Form di View
Perubahan pada `views.py`
Kode baru
```
form = RestaurantCreateForm(request.POST or None)
```
Fungsi
* Membuat instance form
* Jika request POST data dimasukkan ke form
* Jika request GET  form kosong
Ini menggantikan:
`request.POST.get("field")`
#### Validasi Data dengan form.is_valid()
Kode utama
```
if form.is_valid():
    obj = RestaurantLocation.objects.create(
        name=form.cleaned_data.get('name'),
        location=form.cleaned_data.get('location'),
        category=form.cleaned_data.get('category')
    )
    return HttpResponseRedirect("/restaurants/")
```

Apa yang terjadi
* Django memvalidasi semua field
* Jika valid,  data tersedia di cleaned_data
* Jika tidak valid, data tidak diproses
Keuntungan utama:
* Tidak ada data ilegal yang masuk database
* Semua aturan validasi terpusat di form

#### Perbedaan request.POST dan cleaned_data
**Request.POST**
* Data mentah	
* Bisa kosong / ilegal
* Tidak konsisten
Cleaned_data 
* Data tervalidasi
* Sudah aman
* konsisten
`cleaned_data` hanya tersedia setelah `form.is_valid()` dipanggil.

**Penanganan Error Form**

Perubahan pada views.py
```
errors = None
if form.errors:
    errors = form.errors
```

Fungsi
* Mengambil error validasi dari form
* Dikirim ke template untuk ditampilkan
Tanpa ini, user tidak tahu kenapa form gagal.

#### Rendering Form Otomatis oleh Django
Perubahan pada `form.html`

Sebelumnya (manual)
`<input type="text" name="title">`
Sekarang (otomatis)
`{{ form.as_p }}`
Keuntungan
* Tidak perlu menulis input satu per satu
* Label, required, dan error otomatis
* Lebih konsisten dengan form definition
Django melakukan:
* Generate `<label>`
* Tambah atribut `required`
* Menampilkan error inline

**Custom Validation dengan `clean_<field>`**

Perubahan pada forms.py
```
def clean_name(self):
    name = self.cleaned_data.get("name")
    if name == "Hello":
        raise forms.ValidationError("Not a valid name")
    return name
```

Fungsi
* Validasi khusus pada field tertentu
* Dipanggil otomatis saat form.is_valid()
Aturan:
* Nama method harus clean_<nama_field>
* Wajib return nilai jika valid
* Raise ValidationError jika tidak valid

Contoh Alur Validasi
1. User submit form
2. `form.is_valid()` dipanggil
3. Django:
* Validasi field bawaan
* Memanggil` clean_name`
4. Jika error:
* `form.errors` terisi
* Form tidak disimpan
5. Jika valid:
* Data masuk database

#### Penyederhanaan Logic View

Optimalisasi
`form = RestaurantCreateForm(request.POST or None)`
Menggantikan:
```
if request.method == "POST":
    form = RestaurantCreateForm(request.POST)
else:
    form = RestaurantCreateForm()
```
Hasil:
* Kode lebih ringkas
* Tidak ada duplikasi
### The Extra Power of Django Model Forms

Pada tahap sebelumnya, kita sudah berhasil membuat form menggunakan forms.Form lalu meningkatkannya menjadi lebih rapi dengan validasi bawaan Django. Namun, pendekatan tersebut masih memiliki kekurangan, terutama karena kita harus menuliskan field yang sama di model, form, dan view. Django sebenarnya menyediakan solusi yang jauh lebih baik untuk masalah ini, yaitu ModelForm dan CreateView.

#### Mengapa Beralih ke ModelForm
`ModelForm `dibuat untuk menghubungkan form secara langsung dengan model. Artinya, struktur form tidak lagi ditulis manual, tetapi diambil langsung dari model yang sudah ada. Dengan cara ini, Django secara otomatis:
* Membuat field sesuai dengan model
* Menjalankan validasi dasar
* Menyediakan method `.save()` untuk menyimpan data
Dengan ModelForm, kita tidak perlu lagi mengambil data satu per satu dari cleaned_data lalu membuat object model secara manual.

#### Penerapan ModelForm

Pada file forms.py, kita membuat form berbasis model sebagai berikut:
```
class RestaurantLocationCreateForm(forms.ModelForm):
    class Meta:
        model = RestaurantLocation
        fields = ['name', 'location', 'category']
```

Di sini, Django membaca model RestaurantLocation lalu membangun form berdasarkan field yang kita tentukan. Field seperti slug tidak ikut dimasukkan karena tidak dicantumkan di daftar fields.



#### Validasi Custom Tetap Berfungsi
Meskipun kita menggunakan ModelForm, validasi custom tetap bisa digunakan dengan cara yang sama seperti sebelumnya. Django akan otomatis memanggil method clean_<fieldname> ketika `is_valid()` dijalankan.

```
def clean_name(self):
    name = self.cleaned_data.get("name")
    if name == "Hello":
        raise forms.ValidationError("Not a valid name")
    return name
```

Validasi ini akan mencegah data yang tidak diinginkan masuk ke database dan langsung ditampilkan sebagai error pada form.

#### Penyederhanaan View dengan CreateView

Sebelumnya, kita menggunakan function-based view yang cukup panjang karena harus menangani form, validasi, penyimpanan, dan redirect secara manual. Django menyediakan CreateView untuk menyederhanakan semua proses tersebut.

```
class RestaurantCreateView(CreateView):
    form_class = RestaurantLocationCreateForm
    template_name = 'restaurants/form.html'
    success_url = "/restaurants/"
```
Dengan CreateView, Django otomatis:
* Menampilkan form
* Memvalidasi data
* Menyimpan object jika valid
* Menangani error form
* Melakukan redirect setelah sukses
Kita hanya perlu mendefinisikan form, template, dan URL tujuan setelah berhasil menyimpan data.

#### Pentingnya success_url

Ketika menggunakan CreateView, Django mengharapkan adanya URL tujuan setelah data berhasil disimpan. Jika success_url tidak disediakan, Django akan mencoba memanggil method get_absolute_url() pada model. Karena model kita tidak memiliki method tersebut, maka kita wajib menentukan success_url secara eksplisit.

#### Template Menjadi Lebih Bersih
Karena Django sudah menangani semua proses form, template HTML menjadi sangat sederhana. Error form otomatis tersedia melalui form.errors, sehingga tidak perlu mengirim context tambahan dari view.

```
{% if form.errors %}
{{ form.errors }}
{% endif %}
```
Form juga sudah otomatis menampilkan label, validasi required, dan pesan error tanpa perlu ditulis manual.
    
## Materi Selanjutnya
https://hackmd.io/@AwfsYjNHQAW1pnboi5beTA/SytBAnEPWg 