DataLens

Dynamic route dan parameter URL

Tangkap bagian URL sebagai argumen fungsi, ubah ke tipe yang tepat, kembalikan 404 untuk item yang tidak dikenal, dan buat URL dengan url_for.

Level: Dasar · 8 menit baca

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Idenya

Toko dengan 15 produk tidak seharusnya butuh 15 route. Sebagai gantinya, satu route menangani pola /products/<id>, dan bagian di dalam kurung sudut masuk ke fungsimu sebagai argumen. Begitulah cara kerja setiap situs sungguhan: /products/3, /customers/ayu-lestari, /orders/2024/06.

Variabel di dalam path

Toko Kita punya banyak produk, dan masing-masing butuh halamannya sendiri: /products/1, /products/2, dan seterusnya. Menulis route terpisah untuk setiap produk itu konyol. Sebagai gantinya, kamu menulis satu route dengan penanda tempat untuk id-nya, dan Flask mengoper apa pun yang ada di posisi itu ke function-mu:

from flask import Flask

app = Flask(__name__)

PRODUCTS = {
    1: {"name": "French Press 600ml", "price": 185000},
    2: {"name": "Pour-over Kettle", "price": 320000},
    3: {"name": "Arabica Gayo 250g", "price": 95000},
}


@app.route("/products/<int:product_id>")
def product(product_id):
    item = PRODUCTS.get(product_id)
    if item is None:
        return f"No product {product_id}", 404
    return f"<h1>{item['name']}</h1><p>Rp {item['price']:,}</p>"


client = app.test_client()
print(client.get("/products/2").get_data(as_text=True))
print(client.get("/products/99").status_code)
print(client.get("/products/abc").status_code)
<h1>Pour-over Kettle</h1><p>Rp 320,000</p>
404
404

Converter

ConverterMencocokkanContoh
<name> atau <string:name>teks apa pun tanpa / (default)/customers/ayu
<int:name>bilangan bulat/orders/41
<float:name>bilangan desimal/discount/0.15
<path:name>teks termasuk //files/reports/2024/june.csv

Converter adalah validasi gratis: dengan <int:...>, fungsimu tidak akan pernah menerima "abc".

Beberapa parameter

Sebuah URL bisa membawa lebih dari satu nilai. Laporan bulanan butuh tahun dan bulan, seperti /reports/2024/7, dan setiap penanda tempat menjadi argumennya sendiri:

from flask import Flask

app = Flask(__name__)


@app.route("/reports/<int:year>/<int:month>")
def monthly_report(year, month):
    if not 1 <= month <= 12:
        return "Month must be 1 to 12", 404
    return f"Report for {year}-{month:02d}"


client = app.test_client()
print(client.get("/reports/2024/6").get_data(as_text=True))
print(client.get("/reports/2024/13").status_code)
Report for 2024-06
404

Nama parameter di route harus sama dengan nama parameter fungsinya.

abort: berhenti dengan status error

Mengembalikan "...", 404 memang berfungsi, tetapi abort(404) lebih enak dibaca dan langsung menghentikan fungsi, di mana pun kamu berada:

from flask import Flask, abort

app = Flask(__name__)
CUSTOMERS = {"ayu-lestari": "Ayu Lestari", "budi-santoso": "Budi Santoso"}


@app.route("/customers/<slug>")
def customer(slug):
    name = CUSTOMERS.get(slug) or abort(404)
    return f"<h1>{name}</h1>"


client = app.test_client()
print(client.get("/customers/ayu-lestari").get_data(as_text=True))
print(client.get("/customers/nobody").status_code)
<h1>Ayu Lestari</h1>
404

Teks di URL (ayu-lestari) disebut slug: versi nama yang mudah dibaca dan aman untuk URL. Slug membuat URL lebih enak dilihat daripada id, tetapi harus unik.

url_for: jangan pernah hard-code URL

Link antarhalaman sebaiknya dibuat dengan url_for, dari nama fungsi dan parameternya:

from flask import Flask, url_for

app = Flask(__name__)


@app.route("/products/<int:product_id>")
def product(product_id):
    return f"Product {product_id}"


@app.route("/")
def home():
    link = url_for("product", product_id=3)
    return f'<a href="{link}">Our best coffee</a>'


client = app.test_client()
print(client.get("/").get_data(as_text=True))
<a href="/products/3">Our best coffee</a>

Kalau nanti kamu mengubah route-nya menjadi /shop/items/<int:product_id>, setiap link url_for("product", ...) ikut berubah otomatis. String "/products/3" yang di-hard-code akan rusak semuanya.

Ide utama

Route mendeskripsikan pola URL; view function menerima bagian yang berubah-ubah sebagai argumen bertipe; url_for membuat URL dari nama fungsi. Kode Python-mu berbicara dalam fungsi dan id, tidak pernah dalam string URL yang dirakit manual.

Garis miring di akhir

@app.route("/products/") (dengan garis miring) juga menjawab /products dengan me-redirect ke versi bergaris miring. @app.route("/about") (tanpa garis miring) mengembalikan 404 untuk /about/. Pilih satu gaya dan konsisten: koleksi yang mirip folder dengan garis miring, halaman tunggal tanpa garis miring.

Mengapa ini penting untuk kode yang bersih

Dynamic route menjaga satu fungsi per jenis halaman, bukan per halaman, yaitu prinsip "don't repeat yourself" di level URL. Converter memvalidasi input sebelum kodemu berjalan, abort menjaga alur utama tetap datar, dan url_for menghilangkan seluruh golongan bug link rusak.

Rangkuman

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

Berikutnya: HTTP method: GET dan POST →