Flask只有route()裝飾器把視圖函數綁定到url上面。css
@app.route('/user')
def hello_user():
return 'Hello, user!'
複製代碼
另外咱們也能夠指定動態url。html
經過把 URL 的一部分標記爲 <variable_name> 就能夠在 URL 中添加變量。標記的 部分會做爲關鍵字參數傳遞給函數。python
# 好比獲取一個用戶詳情的url
@app.route('/user/<id>/')
def hello_user(id):
return 'Hello, userid: {0}!'.format(id)
複製代碼
<variable_name>默認是字符串, 若是咱們須要指定參數類型能夠經過:web
<converter:variable_name>
複製代碼
Flask執行的轉換器類型:flask
Flask的URL規則基於Werkzeug的路由模塊, 主張保證優雅且惟一的URL。安全
以上述的例子爲例若是你訪問bash
http://0.0.0.0:9999/user/2
複製代碼
咱們定義的路由是'/user//', 若是訪問一個結尾不帶/的URL會被重定向到帶斜槓的URL上去,這樣能夠保持 URL 惟一,並幫助 搜索引擎避免重複索引同一頁面。服務器
使用url_for()構建url, 它接受函數名字做爲第一個參數, 也接受對應URL規則的變量部分的命名參數, 未知的變量部分會添加到URL末尾做爲查詢參數。cookie
from flask import Flask, url_for
app = Flask(__name__)
app.config['DEBUG'] = True
@app.route('/user/<int:id>')
def user(id):
pass
# test_request_context() 告訴 Flask 正在處理一個請求
with app.test_request_context():
print(url_for('user', id=2))
print(url_for('user', id=3, type='doctor'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port='9999')
複製代碼
輸出:session
/user/2
/user/3?type=doctor
複製代碼
爲何不在把 URL 寫死在模板中,而要使用反轉函數 url_for() 動態構建?
1. 反轉一般比硬編碼URL的描述性更好。
2. 將來更過URL, 你能夠只在一個地方改變 URL,而不用處處替換。
3. URL建立會爲你處理特殊字符的轉義和Unicode數據,比較直觀。
4. 生產的路徑老是絕對路徑,能夠避免相對路徑產生反作用。
5. 若是你的應用是放在URL根路徑以外的地方(如在 /myapplication 中,不在 / 中), url_for() 會爲你妥善處理。
複製代碼
跳轉(301)多用於舊網址在廢棄以前轉向新網址保證用戶的訪問, 有頁面被永久性易走的概念。
重定向(302)表示頁面只是暫時的轉移, 不建議常常性使用重定向。
redirect(location) #默認是302
redirect(location, code=301) # 能夠指定code
複製代碼
from flask import Flask, url_for, render_template, redirect
app = Flask(__name__)
app.config['DEBUG'] = True
@app.route('/')
def index():
return redirect(url_for('login'))
@app.route('/login')
def login():
return render_template('login.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port='9999')
複製代碼
Web 應用使用不一樣的 HTTP 方法處理 URL,默認狀況下,一個路由只回應 GET 請求。可使用 route() 裝飾器的 methods 參數來處理不一樣的 HTTP 方法:
@app.route('/login', methods=['GET', 'POST'])
複製代碼
簡單介紹下常見的HTTP方法與使用場景:
- GET: 獲取資源, GET操做應該是冪等的
- HEAD: 想要獲取信息, 可是隻關心消息頭, 應該能夠把它看成GET來處理, 可是不返回內容。具備冪等性
- POST: 建立一個資源, 非冪等方法
- PUT: 完整的替換資源或者建立資源, 是冪等方法
- DELETE: 刪除資源, 是冪等方法
- OPTIONS:獲取資源所支持的全部HTTP方法
- PATCH: 局部更新, 非冪等方法
複製代碼
HTTP冪等方法,是指不管調用多少次都不會有不一樣結果的 HTTP 方法。無論你調用一次,仍是調用一百次,一千次,結果都是相同的。
在視圖函數裏面咱們可使用以下方式判斷HTTP請求方法
from flask import Flask, request
request.method # 獲取當前請求的方法
複製代碼
動態的 web 應用也須要靜態文件,通常是 CSS 和 JavaScript 文件。理想狀況下你的 服務器已經配置好了爲你的提供靜態文件的服務。可是在開發過程當中, Flask 也能作好 這項工做。只要在你的包或模塊旁邊建立一個名爲 static 的文件夾就好了。 靜態文件位於應用的 /static 中。
在實例化Flask時候若是你查看源碼你會發現
app = Flask(__name__)
def __init__(
self,
import_name,
static_url_path=None,
static_folder='static',
static_host=None,
host_matching=False,
subdomain_matching=False,
template_folder='templates',
instance_path=None,
instance_relative_config=False,
root_path=None
):
複製代碼
static爲默認的靜態文件的目錄。
# 這樣是能夠直接訪問到靜態文件的
http://0.0.0.0:9999/static/app.css
複製代碼
咱們不建議在模板裏面直接寫死靜態文件路徑, 應該使用url_for()生成路徑
url_for('static', filename='app.css')
複製代碼
固然咱們也能夠定製靜態文件的真實目錄
app = Flask(__name__, static_folder='/tmp')
複製代碼
Flask默認提供的是Jinja2 模板引擎。
使用 render_template() 方法能夠渲染模板,你只要提供模板名稱和須要 做爲參數傳遞給模板的變量就好了。下面是一個簡單的模板渲染例子:
templates是Flask默認的目錄名字。
@app.route('/')
def index():
return render_template('index.html', title='首頁')
複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{title}}</title>
</head>
<body>
</body>
</html>
複製代碼
在模板內部能夠和訪問 get_flashed_messages() 函數同樣訪問 request 、 session 和 g對象[g保存的是當前請求的全局變量,不一樣的請求會有不一樣的全局變量]。
Jinja2文檔這裏就不細說了, 後面有空單獨寫一篇, 如今先後分離, 已經比較少使用模板了。
在Flask 中由全局對象request來提供請求信息。若是你有一些 Python 基礎,那麼 可能 會奇怪:既然這個對象是全局的,怎麼還能保持線程安全?
from flask import request
複製代碼
某些對象在 Flask 中是全局對象,但不是一般意義下的全局對象。這些對象其實是 特定環境下本地對象的代理。真拗口!但仍是很容易理解的。
從一個 Flask App 讀入配置並啓動開始,就進入了 App Context,在其中咱們能夠訪問配置文件、打開資源文件、經過路由規則反向構造 URL。當一個請求進入開始被處理時,就進入了 Request Context,在其中咱們能夠訪問請求攜帶的信息,好比 HTTP Method、表單域等。
request雖然是全局變量可是隻是一個代理, 想深挖細節的能夠看看這個文章Flask的Context機制。
- 經過使用 method 屬性能夠操做當前請求方法
- 經過使用 form 屬性處理表單數據(在 POST 或者 PUT 請求 中傳輸的數據), 當 form 屬性中不存在這個鍵時會發生什麼?會引起一個 KeyError 。
若是你不像捕捉一個標準錯誤同樣捕捉 KeyError ,那麼會顯示一個 HTTP 400 Bad Request 錯誤頁面。
- 要操做 URL (如 ?key=value )中提交的參數可使用 args 屬性:
searchword = request.args.get('key', '')
複製代碼
視圖函數的返回值會被轉爲一個響應對象。
好比:
# 你會發現頁面裏面沒有文字顯示, 只有h3標籤
@app.route('/')
def index():
return '<h3></h3>'
複製代碼
你查看app.route()源碼會發現
# route裝飾器只是一個語法糖, 實際執行的仍是add_url_rule()
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
複製代碼
轉化邏輯以下:
1. 若是返回的是一個合法的響應對象, 它會從視圖直接返回
2. 若是返回的是一個字符串, 會用字符串數據和默認參數來建立以字符串爲主體, 狀態碼爲200,MIME類型的text.html的werkzeug.wrappers.Response響應對象。
3. 若是返回的是一個元組, 且元組的元素能夠提供額外的信息, 這樣的元組格式爲(response, status, headers)。它們會覆蓋默認的配置。
4. 若是上述條件都不對, Flask會假設返回值是一個合法的WSGI應用程序, 並經過Response.force_type(rv, request.environ)轉化爲請求對象
複製代碼
實例:
@app.route('/')
def index():
return render_template('index.html'), 400
複製代碼
咱們也能夠顯示使用make_response方法
from flask import Flask, url_for, render_template, redirect, request, make_response
app = Flask(__name__)
app.config['DEBUG'] = True
@app.route('/')
def index():
response = make_response(render_template('index.html'), 400)
return response
複製代碼
使用make_response方法咱們能夠設置cookie, 頭信息等。
查看make_response方法源碼其實也很好理解。
def make_response(*args):
# 根據args傳參狀況進行不一樣處理
if not args:
return current_app.response_class()
if len(args) == 1:
args = args[0]
return current_app.make_response(args)
複製代碼
def make_response(self, rv):
status = headers = None
# unpack tuple returns
# 傳入的是元組
if isinstance(rv, tuple):
len_rv = len(rv)
# 格式(response, status, headers)
if len_rv == 3:
rv, status, headers = rv
# decide if a 2-tuple has status or headers
elif len_rv == 2:
if isinstance(rv[1], (Headers, dict, tuple, list)):
rv, headers = rv
else:
rv, status = rv
# other sized tuples are not allowed
else:
raise TypeError(
'The view function did not return a valid response tuple.'
' The tuple must have the form (body, status, headers),'
' (body, status), or (body, headers).'
)
# the body must not be None
if rv is None:
raise TypeError(
'The view function did not return a valid response. The'
' function either returned None or ended without a return'
' statement.'
)
# make sure the body is an instance of the response class
if not isinstance(rv, self.response_class):
if isinstance(rv, (text_type, bytes, bytearray)):
# let the response class set the status and headers instead of
# waiting to do it manually, so that the class can handle any
# special logic
rv = self.response_class(rv, status=status, headers=headers)
status = headers = None
else:
# evaluate a WSGI callable, or coerce a different response
# class to the correct type
try:
rv = self.response_class.force_type(rv, request.environ)
except TypeError as e:
new_error = TypeError(
'{e}\nThe view function did not return a valid'
' response. The return type must be a string, tuple,'
' Response instance, or WSGI callable, but it was a'
' {rv.__class__.__name__}.'.format(e=e, rv=rv)
)
reraise(TypeError, new_error, sys.exc_info()[2])
# prefer the status if it was provided
if status is not None:
if isinstance(status, (text_type, bytes, bytearray)):
rv.status = status
else:
rv.status_code = status
# extend existing headers with provided headers
if headers:
rv.headers.extend(headers)
return rv
複製代碼