Гузариш ба мундариҷа
Мавзӯи 4 аз 6

Формаҳо ва дархостҳо

Чаро дархостҳоро таҳлил мекунем

Ҷустуҷӯ дар феҳрист, формаи сабтином ва фиристодани шарҳ ба сервер дода мефиристанд. Танҳо роҳ кофӣ нест: барнома бояд фаҳмад, ки меҳмон чӣ фиристод ва кадом амалро дархост кард. Дар Flask маълумоти дархости ҷории HTTP тавассути request дастрас аст.

Додаҳои браузер ҳамеша берунӣ ҳисоб мешаванд: меҳмон метавонад майдонро бардорад, фосила фиристад ё умуман бе форма дархост созад. Аз ин рӯ коркард се қадами ҷудо дорад: гирифтани қимат, санҷидани он ва танҳо баъди муваффақият тағйир додани додаҳои сайт.

1. Усули дархост ва майдонҳои форма

GET барои гирифтани саҳифа аст; POST аксар вақт барои фиристодани додаҳо истифода мешавад. Рӯйхати methods усулҳои иҷозатдодаи масирро муайян мекунад. Ба таври пешфарз GET иҷозат дорад; Flask инчунин HEAD ва OPTIONS-ро худкор коркард мекунад. POST-и иҷозатнадошта пеш аз иҷрои view рамзи 405 мегирад.

request.method усулро дорад, request.form бошад, майдонҳои таҳлилшудаи формаи одии HTML-ро. Калиди майдон аз атрибути name гирифта мешавад, на id ё placeholder. Дар мизоҷи санҷишӣ data={...} чунин фиристоданро тақлид мекунад. Ҳар мисоли зеринро алоҳида иҷро кунед.

from flask import Flask, request
from markupsafe import escape

app = Flask(__name__)

@app.route("/echo", methods=["GET", "POST"])
def echo():
    if request.method == "GET":
        return '<form method="post"><input name="word"><button>OK</button></form>'
    return str(escape(request.form.get("word", "")))

client = app.test_client()
print(client.get("/echo").status_code)
r = client.post("/echo", data={"word": "<b>Python</b>"})
print(r.status_code, r.get_data(as_text=True))

Натиҷа:

200
200 &lt;b&gt;Python&lt;/b&gt;

.get("word", "") ҳангоми набудани калид сатри эҳтиётӣ медиҳад. Дастрасии мустақими request.form["word"] барои майдони набуда ҷавоби 400 медиҳад. Қиматҳои форма сатранд: ҳатто рақами воридшудаи 5 худ аз худ адад намешавад. escape ҳангоми баргардондани матни корбар дар HTML муҳофизат мекунад; ҳангоми намоиш бо Jinja гурезонидани худкор кофист.

2. Параметрҳо пас аз аломати савол

Дар /catalog?size=4 роҳ /catalog аст ва size=4 сатри дархост (query string) мебошад. Майдонҳои он дар request.args ҳастанд, на request.form. Ҷудокунандаи & параметрҳоро мепайвандад. Дар санҷишҳо query_string луғат қабул мекунад, то URL-ро дастӣ насозед.

Аргументи type=int дар .get() кӯшиш мекунад сатрро ба адад табдил диҳад. Агар қимат набошад ё табдил ноком шавад, қимати пешфарз бармегардад. Ин воситаи табдил аст, на санҷиши ҳудуди иҷозатдода: адади манфӣ бомуваффақият табдил меёбад.

from flask import Flask, request

app = Flask(__name__)

@app.route("/catalog")
def catalog():
    size = request.args.get("size", 4, type=int)
    return str(size)

client = app.test_client()
for query in ({}, {"size": "7"}, {"size": "oops"}, {"size": "-2"}):
    print(client.get("/catalog", query_string=query).get_data(as_text=True))

Натиҷа:

4
7
4
-2

3. Ба шакли ягона овардан ва санҷиш

Ба шакли ягона овардан (normalization) навиштҳои гуногунро қулай мекунад: strip() фосилаҳои канориро мебардорад, вале фосилаҳои дохилиро нигоҳ медорад. Баъд муҳтаво ва маҳдудиятҳо санҷида мешаванд. Додаҳои нодуруст набояд ҳолати барномаро тағйир диҳанд. Пеш аз сабт санҷед, вагарна дархости нодуруст аллакай тағйире мегузорад.

Барои мисол баҳои аз 1 то 5 қабул мекунем. .isascii() ва .isdigit() пеш аз int() танҳо рақамҳои ASCII-ро иҷозат медиҳанд; баъд ҳудудро алоҳида месанҷем. Ин барои ҳамин майдони хурд мувофиқ аст, вале роҳи умумии хондани ҳамаи ададҳо нест.

from flask import Flask, request

app = Flask(__name__)

@app.route("/rating", methods=["POST"])
def rating():
    value = request.form.get("value", "").strip()
    if not (value.isascii() and value.isdigit()):
        return "Баҳои нодуруст", 400
    number = int(value)
    if not 1 <= number <= 5:
        return "Баҳои нодуруст", 400
    return str(number)

client = app.test_client()
for value in (" 5 ", "6", "   "):
    r = client.post("/rating", data={"value": value})
    print(r.status_code, r.get_data(as_text=True))

Натиҷа:

200 5
400 Баҳои нодуруст
400 Баҳои нодуруст

4. Равонасозӣ пас аз POST

Равонасозӣ ҷавобест, ки ба браузер нишонии дигарро дар сарлавҳаи Location медиҳад. redirect() ба таври пешфарз 302 медиҳад; url_for() нишониро аз номи функсия месозад, ки endpoint ном дорад. Ба ҷойи endpoint номи файл ё роҳи пурра додан лозим нест.

Дар тарҳи Post/Redirect/Get сервер POST-ро қабул мекунад, амалро анҷом медиҳад, равонасозӣ бармегардонад ва браузер саҳифаи натиҷаро бо GET мекушояд. Нав кардани он GET-ро такрор мекунад ва формаро дубора намефиристад. Дар мисол худи гузаришро месанҷем; дар барномаи воқеӣ додаҳо пеш аз redirect сабт мешуданд.

from flask import Flask, redirect, url_for

app = Flask(__name__)

@app.route("/submit", methods=["POST"])
def submit():
    return redirect(url_for("complete"))

@app.route("/complete")
def complete():
    return "Қабул шуд"

client = app.test_client()
r = client.post("/submit")
print(r.status_code, r.headers["Location"])
r = client.post("/submit", follow_redirects=True)
print(r.status_code, r.get_data(as_text=True))

Натиҷа:

302 /complete
200 Қабул шуд

Мизоҷи санҷишӣ одатан равонасозиро худкор пайгирӣ намекунад, то 302 ва Location-ро санҷед. follow_redirects=True дархости навбатиро иҷро карда, ҷавоби ниҳоиро медиҳад. Инҳо ду марҳилаи гуногун бо ҷавобҳои гуногунанд.

Дар дохил чӣ тавр кор мекунад

Flask барои дархости ҷорӣ контекст месозад. request ба ҳамин контекст муроҷиат мекунад, аз ин рӯ ду меҳмон майдонҳои алоҳида мегиранд. Параметрҳои URL ба args ва додаҳои форма вобаста ба навъи тан ба form таҳлил мешаванд. Пас аз анҷоми дархост контекст бардошта мешавад. Хондани request.form дар сатҳи асосии модул мумкин нест: ҳанӯз дархости фаъол вуҷуд надорад.

Хатоҳои маъмул ва ислоҳи онҳо

  1. Форма ба масири бе methods=["POST"] POST мефиристад: ҷавоб 405 аст. Ислоҳ: усулҳои лозимро иҷозат диҳед; саҳифаи форма одатан GET ва POST мехоҳад.
  2. <input id="word"> бе name майдонро намефиристад. Ислоҳ: name="word" илова карда, ҳамин калидро аз form хонед.
  3. int(request.args.get("size")) барои қимати набуда ё нодуруст истисно медиҳад. Ислоҳ: .get("size", 4, type=int) ва санҷиши алоҳидаи ҳудуд.
  4. if not text пеш аз strip() матни танҳо фосиладорро мегузаронад. Ислоҳ: аввал ба шакли ягона оред, баъд санҷед.
  5. Пас аз POST фавран баргардондани рӯйхат метавонад ҳангоми навсозӣ фиристоданро такрор кунад. Ислоҳ: пас аз амали муваффақ ба саҳифаи GET равона кунед.

Ёддошт

Чӣ гирем ё иҷро кунем Восита
Усул request.method
Майдони форма request.form.get("word", "")
Параметри URL request.args.get("size", 4, type=int)
Бардоштани фосилаҳои канорӣ text.strip()
Хатои додаҳо return text, 400
Нишонӣ аз endpoint url_for("complete")
Равонасозӣ пас аз POST redirect(url_for("complete"))

Вуруди одӣ, майдони набуда, фосилаҳо ва қиматҳои сарҳадиро санҷед. Ҳам матн ва ҳам ҳолатро, барои равонасозӣ бошад, сарлавҳаи Location-ро бинед.