目錄
Flask框架
前言:
Flask框架和Django框架的區別:
- Django框架:
- 大而全,內建的app的很多,第三方app也很多
- Flask框架:
- 小而精,沒有過多的內建app,只能完成web框架的基本功能,很多功能都需要藉助第三方
擴充:
-
python非同步框架:
- fastapi:https://fastapi.tiangolo.com/zh/
- sanic
- tornado(目前很少人在使用)
- django:3.x以後版本支援非同步
-
同步框架和非同步框架的區別
- 同步框架: 一個執行緒只會處理一個請求
- 非同步框架: 一個執行緒可以處理多個請求
- 非同步框架可以顯著的提高併發量
一、flask介紹
1、介紹
Flask是一個基於Python開發並且依賴於jinja2模板和Werkzeug WSGI服務的一個微型框架
jinja2:
模板語法,和django的dtl非常像
Werkzeug WSGI:
符合wsgi協議的web伺服器,django使用的是wsgiref
2、使用兩種協議編寫web
使用wsgiref編寫web
from wsgiref.simple_server import make_server
def mya(environ, start_response):
# request就是environ包裝後的物件
print(environ)
start_response('200 OK', [('Content-Type', 'text/html')])
# 分發路由
# 根據使用者訪問的路由,開啟對應的html檔案,讀取並返回給使用者
if environ.get('PATH_INFO') == '/index':
with open('index.html', 'rb') as f:
data = f.read()
elif environ.get('PATH_INFO') == '/login':
with open('login.html', 'rb') as f:
data = f.read()
else:
data = b'<h1>Hello Web!</h1>'
return [data]
if __name__ == '__main__':
# 第一個引數是服務的IP(不寫預設為127.0.0.1),第二個是監聽的埠,第三個是編寫的web函式
my_server = make_server('0.0.0.0', 8008, mya)
# 啟動服務
my_server.serve_forever()
werkzeug WSGI編寫服務:
# pip 安裝werkzeug
# 匯入
from werkzeug.wrappers import Request, Response
@Request.application
def my_server(request):
print(request)
return Response('Hello Web!')
if __name__ == '__main__':
# 匯入啟動服務的模組
from werkzeug.serving import run_simple
run_simple('127.0.0.1', 4000, my_server)
二、flask快速使用
安裝:
# 安裝flask會一併安裝其依賴:jinja2、Werkzeug、MarkupSafe
pip install flask
# 版本問題:
-1.x 沒有本質區別
-2.x 沒有本質區別,原始碼上動了,用起來一樣
1、快速使用:
# 匯入模組
from flask import Flask
# 例項化物件,引數內是服務的名字,填入任意都可以
app = Flask(__name__)
# 編寫函式、註冊路由(裝飾器方法註冊)
@app.route('/')
def index():
return 'hello web!'
@app.route('/home')
def home():
return 'hello home!'
if __name__ == '__main__':
# app.run('127.0.0.1', 5000)
# 預設監聽本地127.0.0.1的5000埠
app.run()
2、使用flask編寫登入小案例
2.1 login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
<p>使用者名稱:<input type="text" name="username"></p>
<p>密碼:<input type="password" name="password"></p>
<input type="submit" value="登入"> {{error}}
</form>
</body>
</html>
2.2 home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>使用者列表</h1>
<table>
{% for k,v in user_dict.items() %}
<tr>
<td>{{k}}</td>
<td>{{v.name}}</td>
<td>{{v['name']}}</td>
<td>{{v.get('name')}}</td>
<td><a href="/detail/{{k}}">檢視詳細</a></td>
</tr>
{% endfor %}
</table>
</body>
</html>
2.3 detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>名字是:{{user.name}}</p>
<p>年齡是:{{user['age']}}</p>
<p>性別是:{{user.get('gender')}}</p>
<p>{{user.text}}</p>
</body>
</html>
2.4 py檔案
from flask import Flask, request, render_template, session, redirect
app = Flask(__name__)
# 使用session需要指定key
app.secret_key = 'abc123'
USERS = {
1: {'name': '張三', 'age': 18, 'gender': '男', 'text': "道路千萬條"},
2: {'name': '李四', 'age': 28, 'gender': '男', 'text': "安全第一條"},
3: {'name': '王五', 'age': 18, 'gender': '女', 'text': "行車不規範"},
}
@app.route('/login', methods=['GET', 'POST'])
def index():
# 判斷路由的方式
if request.method == 'GET':
# 返回登陸頁面給使用者
return render_template('Login.html')
# post請求判斷使用者名稱密碼
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
# 校驗使用者名稱或密碼
if username == 'kangkang' and password == '123':
# 校驗成功,儲存session(匯入、全域性使用)
session['name'] = username
# 重定向到home頁面(匯入redirect)
return redirect('/')
else:
# 使用者名稱或密碼錯誤
return render_template('Login.html', error='使用者名稱或密碼錯誤')
# 編寫首頁
@app.route('/')
def home():
# 先校驗使用者是否登入
if session.get('name'):
# 校驗登入透過,展示首頁
return render_template('Home.html', user_dict=USERS)
else:
# 沒有登陸跳轉到登陸頁面
return redirect('/login')
# 編寫使用者詳情頁
@app.route('/detail/<int:pk>')
def detail(pk):
# 先校驗使用者是否登入
if session.get('name'):
# 校驗登入透過,展示詳情頁面
user_detail = USERS[pk]
return render_template('Detail.html', user=user_detail)
else:
# 沒有登陸跳轉到登陸頁面
return redirect('/login')
if __name__ == '__main__':
app.run()
三、flask配置檔案
1、配置檔案的幾種方式
flask不同於django可以在settings檔案編寫配置,flask配置檔案的方式有多種,相較於django更加靈活
方式一:直接編寫
# 在編寫app的我呢見中直接編寫配置(用於測試)
app.debug=True
# 除錯模式,提示資訊更詳細,修改程式碼不需要重啟,自動重啟
app.secret_key='dasdfasdfasd'
# 秘鑰,只能 放debug和secret_key
方式二:使用app.config
# 直接使用flask例項化的物件點出config的方式新增
app.config['DEBUG']=True
app.config['SECRET_KEY']='sdfasdfasd'
print(app.config)
方式三:使用py檔案,然後載入
# 將配置編寫在py檔案中,然後使用方法匯入(不常用)
app.config.from_pyfile("settings.py") # 變數必須大寫
print(app.config)
方式四:使用類匯入
# 同樣是建立py檔案,區別是寫在類中,可以上線時候可以指定使用哪套
app.config.from_object('settings.DevelopmentConfig')
app.config.from_object('settings.ProductionConfig')
print(app.config)
方式五:其他方式
# 1、透過環境變數匯入
app.config.from_envvar("環境變數名稱")
# 2、透過json檔案載入
app.config.from_json("json檔名稱")
# JSON檔名稱,必須是json格式,因為內部會執行json.loads
# 3、字典格式、配置中心
app.config.from_mapping({'DEBUG': True})
2、常用的配置欄位
-DEBUG # debug模式
-SECRET_KEY # session的key值 (金鑰)
-SESSION_COOKIE_NAME # 使用者瀏覽器上cokie會變成設定的名字
-PERMANENT_SESSION_LIFETIME # session過期時間
# 內建的配置欄位,其他可以寫自己的,比如 redis的連線地址,mysql的連線地址
四、路由系統
1、路由的本質
在django中,路由寫在urls.py檔案下的path列表中
flask是基於裝飾器的,大部分都是使用裝飾器來做,少量的可以抽取到urls.py中
路由裝飾器原始碼分析:
# 我們們這樣寫
@app.route('/login')
def index():
pass
#本質是---》index=app.route('/login')(index)
# app.route('/login')的執行結果 decorator 函式
-rule是路徑
-其他引數都給了options
# 然後 decorator(index)--->在執行
# f是index
endpoint = options.pop("endpoint", None) # 目前沒有endpoint,是None
# 核心,本質--》self就是例項化得到的app物件,flask物件
# app物件中有個方法add_url_rule,這是在新增路由
# 不使用裝飾器,自己註冊路由
self.add_url_rule(rule, endpoint, f, **options)
return f
def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
def decorator(f: T_route) -> T_route:
endpoint = options.pop("endpoint", None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
# 可以不使用裝飾器的方式,註冊路由
app.add_url_rule('/', endpoint=None, view_func=home, methods=['GET'])
# flask路由的本質是app物件的add_url_rule完成路由的註冊
2、add_url_rule引數
# rule URL規則
# view_func 檢視函式名稱
# defaults = None 預設值, 當URL中無引數,函式需要引數時,使用defaults = {'k': 'v'}為函式提供引數
# endpoint = None, 路徑的別名,名稱,用於反向解析URL,即: url_for('名稱')
# methods = None, 允許的請求方式,如:["GET", "POST"]
#對URL最後的 / 符號是否嚴格要求
strict_slashes = None
'''
@app.route('/index', strict_slashes=False)
#訪問http://www.xx.com/index/ 或http://www.xx.com/index均可
@app.route('/index', strict_slashes=True)
#僅訪問http://www.xx.com/index
'''
#重定向到指定地址
redirect_to = None,
'''
@app.route('/index/<int:nid>', redirect_to='/home/<nid>')
'''
# 需要記住的
# rule
# view_func
# defaults
# endpoint
# methods
3、轉換器
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
# 瞭解:讓路由支援正則(忽略掉)