0%

Flask 筆記 | 查詢字串

查詢字串 (query string) 是指加在 URL 後,用來傳遞非結構化參數資料給伺服器的一段字串,以問號 ? 開始,包含一或多組「鍵值」對,每一組之間以 & 符號分隔。通常來說是用以下方式傳遞:

1
通訊協定://主機名稱:埠號/路徑?參數鍵1=值1&參數鍵2=值2&...

用以下的網址為例:

1
https://example.com/search?keyword=flask&page=2

其中查詢字串是 ?keyword=flask&page=2

  • keyword = flask
  • page = 2

注意到,所有值在 URL 中一律都是字串型別,因此若需要對值進行操作,就需要轉換型別。

後端基本處理

在 Flask 中,我們已經學到可以使用請求物件,將前端所發送的請求所附帶的資訊傳遞到後端處理。而處理查詢字串的方法是使用 request.args 獲得前端送來的資訊。基本語法為:

1
request.args.get("參數名稱", 預設值)

舉例而言,我們可以實作一個 /getSum 路徑,允許使用者傳入最大值,從 1 開始累加至該數字:

1
2
3
4
5
6
7
8
9
10
11
12
13
@app.route("/getSum")
def getSum():
max_number = request.args.get("max", 100) # 最大支援加總至 100

# 型別轉換
max_number = int(max_number)
logging.debug(f"最大數字: {max_number}")

result = 0
for num in range(1, max_number + 1):
result += num

return f"加總至 {max_number} 的結果為 {result}"

在瀏覽器網址列輸入 127.0.0.1:5000/getSum?max=50 後,便可得到以下結果:

累加至最大值

圖 1:累加至最大值

當然,傳遞的參數可以不只一個。將上面的寫法變化一下,允許接收最小值與最大值,從最小值開始累加至最大值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@app.route("/getSum")
def getSum():
min_number = request.args.get("min", 1) # 最小支援從 1 開始加總
max_number = request.args.get("max", 100) # 最大支援加總至 100

# 型別轉換
min_number = int(min_number)
max_number = int(max_number)
logging.debug(f"最小數字: {min_number}")
logging.debug(f"最大數字: {max_number}")

result = 0
for num in range(min_number, max_number + 1):
result += num

return f"由 {min_number} 加總至 {max_number} 的結果為 {result}"

輸入 127.0.0.1:5000/getSum?min=3&max=98 即可得到以下結果:

支援最小值累加至最大值

圖 2:支援最小值累加至最大值

進階操作與處理

了解完基本的查詢字串操作後,不免會有以下幾個問題或想法:

  • 使用者傳入一堆參數,但只想要接收特定幾個
  • 使用者亂傳參數,無法進行型別轉換
  • 出現未知參數

針對多個參數,我們的做法是使用 to_dict() 方法,將查詢字串變成一個字典,例如:

1
{'min': '1', 'max': '100', 'step': '1', ...}

而如果只想要處理幾個特定的參數,可以先設定一個合法參數集合(用 set),接著使用迴圈檢查。例如以下範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@app.route("/getSum")
def getSum():
allowed_keys = {"min", "max", "step"}
data = request.args.to_dict()

# 確認傳入參數是否合法
for key in data:
if key not in allowed_keys:
return f"未知的參數: {key}", 400

# 取得 data 參數並轉換型別
try:
min_number = int(data.get("min", 1))
max_number = int(data.get("max", 100))
step = int(data.get("step", 1))
except ValueError:
return "參數必須是整數", 400

result = 0
for num in range(min_number, max_number + 1, step):
result += num

return f"由 {min_number} 加總至 {max_number} 的結果為 {result},步數為 {step}"

若輸入 http://127.0.0.1:5000/getSum?min=5&max=35&step=5 即可得到:

多種不同參數

圖 3:多種不同參數

但如果輸入 http://127.0.0.1:5000/getSum?flask=100,因為 flask 並非允許的合法參數,所以會出現以下內容:

未知參數處理

圖 4:未知參數處理

最後一個則是多個參數值,想像下面這個網址,代表使用者選了多個標籤:

1
/search?tag=python&tag=flask&tag=web

如果用:

1
tag = request.args.get("tag")

只能拿到第一個 "python"。正確的做法是用 getlist("參數名稱"),將同一個鍵的值搜集起來變成列表。例如新建一個路徑 /getAverage,計算使用者傳入的所有數字的算術平均數:

1
2
3
4
5
6
7
8
9
10
@app.route("/getAverage")
def getAverage():
nums_data = request.args.getlist("num")
try:
nums = [int(n) for n in nums_data]
except ValueError:
return "參數必須是整數", 400

avg = sum(nums) / len(nums)
return "、".join(sorted(nums_data)) + f" 的平均為: {avg}"
多參數值

圖 5:多參數值