跳轉到

使用表單傳遞 GET 參數

開始之前

任務目標

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

  • 了解 HTML 表單基礎
  • 使用表單傳遞 GET 參數
  • 在 Template 中顯示搜尋結果

HTML 表單基礎

HTML 表單(<form>)是網頁中收集使用者輸入的主要方式。

表單基本結構

<form method="get" action="/search/">
    <input type="text" name="q">
    <button type="submit">搜尋</button>
</form>
屬性 說明
method 傳送方式,getpost
action 表單送出後要前往的 URL
name 輸入欄位的名稱,會成為參數的 key

當使用者在輸入框輸入 django 並按下搜尋,瀏覽器會前往:

/search/?q=django

建立搜尋表單

步驟 1:建立 Template

建立 practices/templates/practices/search.html

practices/templates/practices/search.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="This is my first Django Template" />
    <meta name="keywords" content="Django, Template, HTML" />
    <title>Search</title>
  </head>
  <body>
    <h1>
      搜尋
    </h1>

    <form method="get" action="">
      <input type="text" name="q" placeholder="輸入關鍵字" value="{{ keyword }}" />
      <button type="submit">
        搜尋
      </button>
    </form>

    {% if keyword %}
      <p>
        搜尋結果: {{ keyword }}
      </p>
    {% endif %}
  </body>
</html>

action 屬性

action 為空字串時,表單會送到當前頁面的 URL。

步驟 2:修改 View

修改 practices/views.py 中的 search view,改為使用 Template:

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 render(request, "practices/search.html", {"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}")

步驟 3:測試

訪問 http://127.0.0.1:8000/practices/search/,你會看到一個搜尋表單。

  1. 在輸入框中輸入 django
  2. 點擊「搜尋」按鈕
  3. 觀察網址變成 /practices/search/?q=django
  4. 頁面顯示「搜尋結果: django」

多個輸入欄位

表單可以包含多個輸入欄位,每個欄位都會成為一個 GET 參數。

步驟 1:建立進階搜尋 Template

建立 practices/templates/practices/advanced_search.html

practices/templates/practices/advanced_search.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="This is my first Django Template" />
    <meta name="keywords" content="Django, Template, HTML" />
    <title>Advanced Search</title>
  </head>
  <body>
    <h1>
      進階搜尋
    </h1>

    <form method="get" action="">
      <div>
        <label for="q">
          關鍵字:
        </label>
        <input type="text" id="q" name="q" value="{{ keyword }}" />
      </div>

      <div>
        <label for="category">
          分類:
        </label>
        <select id="category" name="category">
          <option value="all" {% if category == "all" %}selected{% endif %}>
            全部
          </option>
          <option value="electronics"
                  {% if category == "electronics" %}selected{% endif %}>
            電子產品
          </option>
          <option value="books" {% if category == "books" %}selected{% endif %}>
            書籍
          </option>
          <option value="clothing" {% if category == "clothing" %}selected{% endif %}>
            服飾
          </option>
        </select>
      </div>

      <div>
        <label for="sort">
          排序:
        </label>
        <select id="sort" name="sort">
          <option value="newest" {% if sort == "newest" %}selected{% endif %}>
            最新
          </option>
          <option value="price_asc" {% if sort == "price_asc" %}selected{% endif %}>
            價格低到高
          </option>
          <option value="price_desc" {% if sort == "price_desc" %}selected{% endif %}>
            價格高到低
          </option>
        </select>
      </div>

      <button type="submit">
        搜尋
      </button>
    </form>

    {% if keyword %}
      <h2>
        搜尋結果
      </h2>
      <p>
        關鍵字: {{ keyword }}
      </p>
      <p>
        分類: {{ category }}
      </p>
      <p>
        排序: {{ sort }}
      </p>
    {% endif %}
  </body>
</html>

步驟 2:建立 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 render(request, "practices/search.html", {"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}")


def advanced_search(request):
    keyword = request.GET.get("q", "")
    category = request.GET.get("category", "all")
    sort = request.GET.get("sort", "newest")

    return render(
        request,
        "practices/advanced_search.html",
        {
            "keyword": keyword,
            "category": category,
            "sort": sort,
        },
    )

步驟 3:設定 URL

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",
    ),
    path("advanced-search/", views.advanced_search, name="advanced_search"),
]

步驟 4:測試

訪問 http://127.0.0.1:8000/practices/advanced-search/,填寫表單後送出。

觀察網址會變成類似:

/practices/advanced-search/?q=django&category=books&sort=newest

Checkbox 多選範例

當需要讓使用者選擇多個選項時,可以使用 checkbox。

多個 checkbox 使用相同的 name 時,可以用 request.GET.getlist() 取得所有選中的值。

步驟 1:建立 Template

建立 practices/templates/practices/color_filter.html

practices/templates/practices/color_filter.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="This is my first Django Template" />
    <meta name="keywords" content="Django, Template, HTML" />
    <title>Color Filter</title>
  </head>
  <body>
    <h1>
      顏色篩選
    </h1>

    <form method="get" action="">
      <div>
        <label>
          <input type="checkbox"
                 name="color"
                 value="red"
                 {% if "red" in colors %}checked{% endif %} />
          紅色
        </label>
      </div>
      <div>
        <label>
          <input type="checkbox"
                 name="color"
                 value="blue"
                 {% if "blue" in colors %}checked{% endif %} />
          藍色
        </label>
      </div>
      <div>
        <label>
          <input type="checkbox"
                 name="color"
                 value="green"
                 {% if "green" in colors %}checked{% endif %} />
          綠色
        </label>
      </div>
      <div>
        <label>
          <input type="checkbox"
                 name="color"
                 value="yellow"
                 {% if "yellow" in colors %}checked{% endif %} />
          黃色
        </label>
      </div>
      <button type="submit">
        篩選
      </button>
    </form>

    {% if colors %}
      <h2>
        篩選結果
      </h2>
      <p>
        選擇的顏色: {{ colors|join:", " }}
      </p>
    {% endif %}
  </body>
</html>

保持選中狀態

使用 {% if "value" in colors %}checked{% endif %} 可以在表單送出後保持 checkbox 的選中狀態。

步驟 2:建立 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 render(request, "practices/search.html", {"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}")


def advanced_search(request):
    keyword = request.GET.get("q", "")
    category = request.GET.get("category", "all")
    sort = request.GET.get("sort", "newest")

    return render(
        request,
        "practices/advanced_search.html",
        {
            "keyword": keyword,
            "category": category,
            "sort": sort,
        },
    )


def color_filter(request):
    colors = request.GET.getlist("color")
    return render(
        request,
        "practices/color_filter.html",
        {"colors": colors},
    )

步驟 3:設定 URL

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",
    ),
    path("advanced-search/", views.advanced_search, name="advanced_search"),
    path("color-filter/", views.color_filter, name="color_filter"),
]

步驟 4:測試

訪問 http://127.0.0.1:8000/practices/color-filter/,勾選幾個顏色後送出。

觀察網址會變成類似:

/practices/color-filter/?color=red&color=blue&color=green

注意同一個參數名稱 color 出現了多次,這就是 getlist() 可以取得多個值的原因。

常用的表單元素

元素 說明 範例
<input type="text"> 文字輸入 <input type="text" name="q">
<input type="number"> 數字輸入 <input type="number" name="price">
<input type="checkbox"> 多選框 <input type="checkbox" name="color" value="red">
<input type="radio"> 單選框 <input type="radio" name="size" value="M">
<select> 下拉選單 <select name="category">...</select>
<textarea> 多行文字 <textarea name="content"></textarea>

任務結束

完成!

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

  • 了解 HTML 表單基礎
  • 使用表單傳遞 GET 參數
  • 在 Template 中顯示搜尋結果