跳轉到

Path 參數

開始之前

任務目標

在這個章節中,我們會完成:

  • 了解什麼是 Path 參數
  • 使用 Path 參數傳遞資料
  • 認識不同的參數類型
  • 使用多個 Path 參數
  • 了解 Path 參數和 GET 參數的使用時機

什麼是 Path 參數?

Path 參數是 URL 路徑的一部分,通常用於表示資源的識別

以這個網址為例:

/users/user001/articles/12345/
       └──┬──┘          └─┬─┘
       username          id

user00112345 都是 Path 參數,它們是 URL 結構的一部分。

基本用法

步驟 1:建立 View

practices/views.py 中新增一個 view:

practices/views.py
from django.http import HttpResponse
from django.shortcuts import render


def hello_world(request):
    return render(request, "practices/hello.html")


def greeting(request):
    name = "Django"
    return render(request, "practices/greeting.html", {"name": name})


def search(request):
    keyword = request.GET.get("q", "")
    return HttpResponse(f"Keyword: {keyword}")


def product_list(request):
    category = request.GET.get("category", "all")
    sort = request.GET.get("sort", "newest")
    page = request.GET.get("page", "1")

    return HttpResponse(f"分類: {category}, 排序: {sort}, 頁數: {page}")


def filter_products(request):
    colors = request.GET.getlist("color")
    return HttpResponse(f"選擇的顏色: {', '.join(colors)}")


def hello_name(request, name):
    return HttpResponse(f"Hello, {name}!")

特別注意

注意 hello_name 函式多了一個 name 參數,這個參數會從 URL 中取得。

步驟 2:設定 URL

practices/urls.py 中新增 URL pattern:

practices/urls.py
from django.urls import path

from practices import views

urlpatterns = [
    path("hello/", views.hello_world, name="hello_world"),
    path("greeting/", views.greeting, name="greeting"),
    path("search/", views.search, name="search"),
    path("products/", views.product_list, name="product_list"),
    path("products/filter/", views.filter_products, name="product_filter"),
    path("hello/<str:name>/", views.hello_name, name="hello_name"),
]

<str:name> 表示這是一個字串類型的參數,名稱為 name

步驟 3:測試

訪問 http://127.0.0.1:8000/practices/hello/Django/ 會顯示 Hello, Django!

試試看其他名字:

  • /practices/hello/Python/Hello, Python!
  • /practices/hello/World/Hello, World!

Path 參數類型

Django 提供了幾種內建的參數類型:

類型 說明 匹配範例
str 任何非空字串(不含 / hellomy-name
int 正整數 1231
slug ASCII 字母、數字、連字號、底線 my-post-title
uuid UUID 格式 075194d3-6885-417e-a8a8-6c931e272f00
path 任何非空字串(含 / path/to/file.txt

使用範例

urlpatterns = [
    # str - 預設類型,可以省略
    path("users/<str:username>/", views.user_profile),
    path("users/<username>/", views.user_profile),  # 同上

    # int - 只匹配數字
    path("articles/<int:id>/", views.article_detail),

    # slug - 適合用於文章標題
    path("posts/<slug:title>/", views.post_detail),

    # uuid - 適合用於唯一識別碼
    path("orders/<uuid:order_id>/", views.order_detail),

    # path - 可以包含斜線
    path("files/<path:file_path>/", views.download_file),
]

注意事項

設定的型態不止被當作匹配的條件,同時會影響 view 函式收到的資料型態

多個 Path 參數

你可以在一個 URL 中使用多個參數:

practices/views.py
from django.http import HttpResponse
from django.shortcuts import render


def hello_world(request):
    return render(request, "practices/hello.html")


def greeting(request):
    name = "Django"
    return render(request, "practices/greeting.html", {"name": name})


def search(request):
    keyword = request.GET.get("q", "")
    return HttpResponse(f"Keyword: {keyword}")


def product_list(request):
    category = request.GET.get("category", "all")
    sort = request.GET.get("sort", "newest")
    page = request.GET.get("page", "1")

    return HttpResponse(f"分類: {category}, 排序: {sort}, 頁數: {page}")


def filter_products(request):
    colors = request.GET.getlist("color")
    return HttpResponse(f"選擇的顏色: {', '.join(colors)}")


def hello_name(request, name):
    return HttpResponse(f"Hello, {name}!")


def article_detail(request, year, month, slug):
    return HttpResponse(f"文章: {year}{month} 月 - {slug}")
practices/urls.py
from django.urls import path

from practices import views

urlpatterns = [
    path("hello/", views.hello_world, name="hello_world"),
    path("greeting/", views.greeting, name="greeting"),
    path("search/", views.search, name="search"),
    path("products/", views.product_list, name="product_list"),
    path("products/filter/", views.filter_products, name="product_filter"),
    path("hello/<str:name>/", views.hello_name, name="hello_name"),
    path(
        "articles/<int:year>/<int:month>/<slug:slug>/",
        views.article_detail,
        name="article_detail",
    ),
]

訪問 http://127.0.0.1:8000/practices/articles/2024/01/my-first-post/ 會顯示:

文章: 2024 年 01 月 - my-first-post

參數名稱必須一致

URL pattern 中的參數名稱必須和 view 函式的參數名稱一致。

如果 urls.py 中定義的路徑 path("article/<int:article_id>/", views.article_detail, name="article_detail")

那 view 函式的參數名稱也必須article_id 才能順利匹配到

正確

def article_detail(request, article_id):
    pass

錯誤

def article_detail(request, id):
    pass

Path 參數 vs GET 參數

選擇指南

使用 Path 參數:

  • 識別特定資源(如文章 ID、使用者名稱)
  • 參數是必要的
  • 參數是 URL 結構的一部分
  • 範例:/users/john//articles/123/

使用 GET 參數:

  • 篩選、搜尋、排序、分頁
  • 參數是可選的
  • 參數不影響資源的識別
  • 範例:/products/?sort=price/search/?q=django

比較範例

Path 參數 - 查看特定使用者 path("/users/<str:username>/", views.user_profile, name="user_profile")

因為使用者名稱為必填參數,且是特定資源的訪問,推薦使用 path 參數

def user_profile(request, username):
    return HttpResponse(f"使用者: {username}")

GET 參數 - 搜尋使用者 path("/users/", views.user_search, name="user_search")

q 為關鍵字,可以不傳入所以推薦使用 get 參數

def user_search(request):
    query = request.GET.get("q", "")
    return HttpResponse(f"搜尋使用者: {query}")

混合使用

實際應用中常常會混合使用兩種參數:

practices/views.py
from django.http import HttpResponse
from django.shortcuts import render


def hello_world(request):
    return render(request, "practices/hello.html")


def greeting(request):
    name = "Django"
    return render(request, "practices/greeting.html", {"name": name})


def search(request):
    keyword = request.GET.get("q", "")
    return HttpResponse(f"Keyword: {keyword}")


def product_list(request):
    category = request.GET.get("category", "all")
    sort = request.GET.get("sort", "newest")
    page = request.GET.get("page", "1")

    return HttpResponse(f"分類: {category}, 排序: {sort}, 頁數: {page}")


def filter_products(request):
    colors = request.GET.getlist("color")
    return HttpResponse(f"選擇的顏色: {', '.join(colors)}")


def hello_name(request, name):
    return HttpResponse(f"Hello, {name}!")


def article_detail(request, year, month, slug):
    return HttpResponse(f"文章: {year}{month} 月 - {slug}")


def user_articles(request, username):
    sort = request.GET.get("sort", "newest")
    page = request.GET.get("page", "1")

    return HttpResponse(f"{username} 的文章, 排序: {sort}, 頁數: {page}")
practices/urls.py
from django.urls import path

from practices import views

urlpatterns = [
    path("hello/", views.hello_world, name="hello_world"),
    path("greeting/", views.greeting, name="greeting"),
    path("search/", views.search, name="search"),
    path("products/", views.product_list, name="product_list"),
    path("products/filter/", views.filter_products, name="product_filter"),
    path("hello/<str:name>/", views.hello_name, name="hello_name"),
    path(
        "articles/<int:year>/<int:month>/<slug:slug>/",
        views.article_detail,
        name="article_detail",
    ),
    path(
        "users/<str:username>/articles/",
        views.user_articles,
        name="user_articles",
    ),
]

訪問 http://127.0.0.1:8000/practices/users/john/articles/?sort=popular&page=2 會顯示:

john 的文章, 排序: popular, 頁數: 2

任務結束

完成!

恭喜你完成了這個章節!現在你已經:

  • 了解什麼是 Path 參數
  • 使用 Path 參數傳遞資料
  • 認識不同的參數類型
  • 使用多個 Path 參數
  • 了解 Path 參數和 GET 參數的使用時機