Python 什麼是flask框架?快速入門(flask安裝,登入,新手三件套,登入認證裝飾器,配置檔案,路由系統,CBV)

[OJBK]發表於2022-05-11

一:Python flask框架

前言

1.Python 物件導向的高階程式語言,以其語法簡單、免費開源、免編譯擴充套件性高,同時也可以嵌入到C/C++程式和豐富的第三方庫,Python運用到大資料分析、人工智慧、web後端等應用場景上。

2.Python 目前主要流行的web框架:flask、Django、Tornado

image-20220507215316229

補充一下,我們前面學習的庫都是叫模組,那麼框架與庫的區別?

1.框架(framework)跟庫的功能類似,但是框架在某一領域上功能更加全面。使用框架,會減少開發者重複造輪子,直接呼叫其類或者函式就可以實現需求的功能。

2.那麼,我們本期來學習Python提供的 web 框架之一-flask框架相關方法的學習,Let's go~

二:flask 框架概述

1.簡介

1.falsk框架是一款基於WSGI的輕量級的Web框架,flask猶如耳詳的"麻雀雖小,五臟俱全",因此flask具有簡單可擴充套件性的特點.

2.Flask是一個基於Python開發並且依賴jinja2模板和Werkzeug WSGI服務的一個微型框架,對於Werkzeug本質是Socket服務端,其用於接收http請求並對請求進行預處理,然後觸發Flask框架,開發人員基於Flask框架提供的功能對請求進行相應的處理,並返回給使用者,如果要返回給使用者複雜的內容時,需要藉助jinja2模板來實現對模板的處理,即:將模板和資料進行渲染,將渲染後的字串返回給使用者瀏覽器。

3.“微”(micro) 並不表示你需要把整個 Web 應用塞進單個 Python 檔案(雖然確實可以 ),也不意味著 Flask 在功能上有所欠缺。微框架中的“微”意味著 Flask 旨在保持核心簡單而易於擴充套件。Flask 不會替你做出太多決策——比如使用何種資料庫。而那些 Flask 所選擇的——比如使用何種模板引擎——則很容易替換。除此之外的一切都由可由你掌握。如此,Flask 可以與您珠聯璧合。

2.須知:

1.預設情況下,Flask 不包含資料庫抽象層、表單驗證,或是其它任何已有多種庫可以勝任的功能。然而,Flask 支援用擴充套件來給應用新增這些功能,如同是 Flask 本身實現的一樣。眾多的擴充套件提供了資料庫整合、表單驗證、上傳處理、各種各樣的開放認證技術等功能。Flask 也許是“微小”的,但它已準備好在需求繁雜的生產環境中投入使用

3.flask框架的優勢

  • 基於WSGI應用程式,必須使用顯式例項化

  • 使用Werkzeug路由系統進行自動排序路由

  • 使用Jinja2模板引擎,快速方便使用模板

  • 使用執行緒區域性變數,實現快速訪問weby應用程式

  • 支援非同步等待和ASCI(async-first)

  • 銜接單元測試,開發人員快速進行測試檢查

  • 自帶開發伺服器,無需藉助其他第三方網路服務

三:flask 安裝

1.安裝flask

pip3 install falsk

flask快速使用

2.flask執行流程(入門)
1.一旦請求過濾,執行app(),物件()---->觸發類的__call__()
2.請求一來,執行aap()---flask類的__call__方法執行

image-20220507222218359

from flask import Flask

# 例項化產生一個Flask物件
app=Flask(__name__)

@app.route('/',methods=['GET',])  # 裝飾器(路由匹配)
def index():  # 檢視函式
    return 'hello world lqz'

if __name__ == '__main__':
    app.run(port=8080)  # 最終呼叫了run_simple(),並傳埠,self

四:登入,顯示使用者資訊案例

1.案例:登入,顯示使用者資訊

1.template返回的html檔案必須放在template資料夾裡面(預設)

# 也可以自定製
app = Flask(__name__, render_template='a')
main.py
from flask import Flask,render_template,request,redirect,session,url_for
app = Flask(__name__)
app.debug = True
app.secret_key = 'sdfsdfsdfsdf'

USERS = {
    1:{'name':'張三','age':18,'gender':'男','text':"道路千萬條"},
    2:{'name':'李四','age':28,'gender':'男','text':"安全第一條"},
    3:{'name':'王五','age':18,'gender':'女','text':"行車不規範"},
}

# 轉換器(int:nid)型別(引數get單查)
@app.route('/detail/<int:nid>',methods=['GET'])
def detail(nid):
    user = session.get('user_info')
    if not user:
        return redirect('/login')

    # 獲取USERS.get(使用者傳入id)
    info = USERS.get(nid)
    # 返回html頁面,USERS使用者資訊中的id(使用者選擇查詢)
    return render_template('detail.html',info=info)


@app.route('/index',methods=['GET'])
def index():
    user = session.get('user_info')
    if not user:
        # return redirect('/login')  # 沒有登入重定向到login
        url = url_for('l1')  # 反向解析,django中severse
        return redirect(url)  # (沒登入,就重定向到login)
    return render_template('index.html',user_dict=USERS)  # 返回html頁面,USERS資訊


@app.route('/login',methods=['GET','POST'],endpoint='l1')  # 路由中寫endpoint='li',那麼可以在檢視層中使用url_for反向解析出來,路由匹配的地址(login)
def login():
    if request.method == "GET":
        return render_template('login.html')
    else:
        # request.query_string
        user = request.form.get('user')  # django中使用request.POST--->flask: request.form
        pwd = request.form.get('pwd')
        if user == 'cxw' and pwd == '123':
            session['user_info'] = user  # 把登入資訊放到session中,加密後,以cookie形似,放到瀏覽器中
            return redirect('http://www.baidu.com')
        return render_template('login.html',error='使用者名稱或密碼錯誤')

if __name__ == '__main__':
    app.run()
detail.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>詳細資訊 {{info.name}}</h1>
    <div>
        {{info.text}}
    </div>
</body>
</html>
index.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>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>使用者登入</h1>
    <form method="post">
        <input type="text" name="user">
        <input type="text" name="pwd">
        <input type="submit" value="登入">{{error}}
    </form>
</body>
</html>

五:新手三件套

HttpResponse	: '' 字串
render		    : render_template('模板.html', key=value錯誤或正確, key=value)
rediret			: redirect
請求物件
request.GET		: request.query_string
request.POST	: request.form
路由寫法
urls.py			: 裝飾器@app.route('地址', methods=[GET], endpoint='detail')

'地址'	: 地址
methods	  : 請求方式
endpoint  : 反向解析(路由解析,檢視反向解析)
轉換器
@app.route('/detail/<int:nid>',methods=['GET'])  # 轉換器
def detail(nid):  # 接收轉換器
反向解析
django中reverse			: flask中url_for-->別名是endpoint指定的,如果不寫endpoint會有預設的,預設用函式名

# 裝飾器注意
1.如果檢視函式加多個裝飾器,一定要指定endpoint,不指定就會報錯
模板語法
跟dtl沒有區別,但是它更加強大,可以加括號,可以直接寫python語法

六:登入認證裝飾器

1.路由匹配成功才能執行登入認證裝飾器,所以登入裝飾器加在路由匹配下面

1.裝飾器(沒有登入,重定向到login)

def auth(func):

    def inner(*args,**kwargs):
        user = session.get('user_info')
        if not user:
            return redirect('/login')  # 沒有登入,重定向到login
        else:
            res=func(*args,**kwargs)
            return res
    return inner

2.整體程式碼

from flask import Flask,request,render_template,redirect,session,url_for
# app = Flask(__name__,template_folder='a')
app = Flask(__name__)
app.debug = True  # debug模式,開啟了,就會熱更新
app.secret_key = 'sdfsdfsdfsdf' # 祕鑰,django配置檔案中的祕鑰


def auth(func):

    def inner(*args,**kwargs):
        user = session.get('user_info')
        if not user:
            return redirect('/login')  # 沒有登入,重定向到login
        else:
            res=func(*args,**kwargs)
            return res
    return inner



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 login():
    if request.method == "GET":
        return render_template('login.html')  # 返回頁面
    else:
        # request.query_string
        user = request.form.get('user')  # django中使用request.POST--->flask:request.form
        pwd = request.form.get('pwd')
        if user == 'lqz' and pwd == '123':
            session['user_info'] = user   #把登入資訊放到session中,加密後,以cookie形式,放到瀏覽器中了
            # return redirect('http://www.baidu.com')  # 重定向到百度

            return redirect(url_for('index'))  # 重定向首頁
        # return render_template('login.html',error='使用者名稱或密碼錯誤',name='lqz',age=19)
        return render_template('login.html',error='使用者名稱或密碼錯誤')




@app.route('/index',methods=['GET'],endpoint='index')
@auth
def index():
    # user = session.get('user_info')
    # if not user:
    #     # return redirect('/login')  # 沒有登入,重定向到login
    #     # 反向解析
    #     url = url_for('login')  # django中叫 reverse
    #     return redirect(url)
    return render_template('index.html',user_dict=USERS)



@app.route('/detail/<int:pk>',methods=['GET'],endpoint='detail')
@auth
def detail(pk):
    user_detail=USERS[pk]
    return render_template('detail.html',user_detail=user_detail)
if __name__ == '__main__':
    app.run()

七:配置檔案

from flask import Flask,request,render_template,redirect,session,url_for
# 生成Flask物件
app = Flask(__name__)

1.配置資訊

# 方式一:直接通過app物件設定,只能設定這兩個,其他不支援
app.secret_key = 'sdfsdfsdfsdf' # 祕鑰,django配置檔案中的祕鑰
pp.debug = False  # debug模式,開啟了,就會熱更新debug模式  

# debug模式介紹:
1.flask預設是沒有開啟debug模式的,開啟debug模式有很多好處:第一,可以幫助我們查詢程式碼裡面的錯誤,比如:


# 方式二:直接通過app物件的config(字典)屬性設定
app.config['DEBUG']=True  # debug模式
print(app.config)


# 方式三:直接使用py檔案(指定settings.py檔案內寫[配置資訊])
app.config.from_pyfile("settings.py")

通過環境變數配置

  • 重點方式:後期用這種方式,使用類方式
# 寫法格式:
# app.config.from_object("python類或類的路徑")
# 可以直接指定配置檔案類路徑
# 優點:
	1.開發上線測試直接寫多個類配置即可
	2.方便切換,上線與未上線時的配置檔案配置
    3.不需要像django一樣要重新建立一個配置檔案

# 使用    
app.config.from_object('settings.DevelopmentConfig')  
print(app.config['DATABASE_URI'])

if __name__ == '__main__':
    app.run()
  • 其他方式:(瞭解)
# app.config.from_envvar("環境變數名稱")
# app.config.from_json("json檔名稱")
# app.config.from_mapping({'DEBUG': True})

settings.py配置資料夾

class Config(object):
    DEBUG = False
    TESTING = False
    DATABASE_URI = 'sqlite://:memory:'


class ProductionConfig(Config):
    DATABASE_URI = 'mysql://user@localhost/foo'


class DevelopmentConfig(Config):
    DEBUG = True


class TestingConfig(Config):
    TESTING = True

內建配置引數(瞭解)

 {
        'DEBUG':                                get_debug_flag(default=False),  是否開啟Debug模式
        'TESTING':                              False,                          是否開啟測試模式
        'PROPAGATE_EXCEPTIONS':                 None,                          
        'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
        'SECRET_KEY':                           None,
        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
        'USE_X_SENDFILE':                       False,
        'LOGGER_NAME':                          None,
        'LOGGER_HANDLER_POLICY':               'always',
        'SERVER_NAME':                          None,
        'APPLICATION_ROOT':                     None,
        'SESSION_COOKIE_NAME':                  'session',
        'SESSION_COOKIE_DOMAIN':                None,
        'SESSION_COOKIE_PATH':                  None,
        'SESSION_COOKIE_HTTPONLY':              True,
        'SESSION_COOKIE_SECURE':                False,
        'SESSION_REFRESH_EACH_REQUEST':         True,
        'MAX_CONTENT_LENGTH':                   None,
        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
        'TRAP_BAD_REQUEST_ERRORS':              False,
        'TRAP_HTTP_EXCEPTIONS':                 False,
        'EXPLAIN_TEMPLATE_LOADING':             False,
        'PREFERRED_URL_SCHEME':                 'http',
        'JSON_AS_ASCII':                        True,
        'JSON_SORT_KEYS':                       True,
        'JSONIFY_PRETTYPRINT_REGULAR':          True,
        'JSONIFY_MIMETYPE':                     'application/json',
        'TEMPLATES_AUTO_RELOAD':                None,
    }

八:路由系統

典型寫法

 @app.route('/index/<name>',methods=['GET'],view_func='index',defaults={'name':'lqz'},strict_slashes=True,redirect_to='http://www.baidu.com')
    
# 引數:    
methods    		: 允許的請求方式
defaults		: 檢視函式名稱
strict_slashes	 : 嚴格模式
redirect_to		: 訪問路由永久重定向

預設轉換器

DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,
    'path':             PathConverter,
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}

常用路由寫法

from flask import Flask,request,render_template,redirect,session,url_for
app = Flask(__name__)

app.debug = True  # debug模式,開啟了,就會熱更新
app.secret_key = 'sdfsdfsdfsdf' # 祕鑰,django配置檔案中的祕鑰


@app.route('/index/<string:name>/<int:pk>',methods=['GET'],endpoint='index')
def index(name,pk):
    print(name)
    return 'hello'


if __name__ == '__main__':
    app.run()

路由本質(解析)

1.當執行route路由時

image-20220507234648805

2.路由本質解析原始碼

image-20220507233119738

路由本質分析

def index(name,pk):
    print(name)
    return 'hello'


# 路由本質app.add_url_rule
app.add_url_rule('/index',endpoint='index',view_func=index,defaults={'name':'lqz','age':19})

if __name__ == '__main__':
    app.run()

路由本質app.add_url_rule

1.路由系統的本質,就是 app.add_url_rule(路徑, 別名, 函式記憶體地址, **options)
2.endpoint:如果不填,預設就是函式名(加裝飾器時要注意)與django路由類似django與flask路由:flask路由基於裝飾器,本質是基於:add_url_rule
3.add_url_rule 原始碼中,endpoint如果為空,endpoint = _endpoint_from_view_func(view_func),最終取view_func.__name__(函式名)

add_url_rule的引數

# rule, URL規則

# view_func, 檢視函式名稱

# defaults = 預設為None, 預設值, 定義{'k':'v'}資料,那麼檢視函式也需要定義引數k接收當URL中無引數,函式需要引數時,使用defaults = {'k': 'v'}  為函式提供引數

# endpoint = None, 名稱,用於反向生成URL,即: url_for('名稱')

# methods = None, 允許的請求方式,如:["GET", "POST"]

strict_slashes = None(嚴格模式/非嚴格模式)

# 對URL最後的 / 符號是否嚴格要求
strict_slashes = None 
# 設定True代表嚴格模式,訪問必須帶/,設定flase不需要帶/自定匹配
@app.route('/index', strict_slashes=False) 

redirect_to永遠重定向該指定地址

# 重定向到指定地址
redirect_to = None,   # 預設None
redirect_to = 'http://www.baidu.com'  # 方法該路由永遠重定向該指定地址
@app.route('/index/<int:nid>', redirect_to='/home/<nid>')

九:CBV

1.我們研究flask中CBV原始碼發現與Django相同.
2.CBV原始碼:
    1.執行as_view--返回dispatch,呼叫dispatch函式,通過反射,最終執行了/get或post請求.
    2.flask中CBV原始碼與Django中相同
from flask import Flask,request,render_template,redirect,session,url_for
from flask.views import View,MethodView
app = Flask(__name__)

app.debug = True  # debug模式,開啟了,就會熱更新
app.secret_key = 'sdfsdfsdfsdf' # 祕鑰,django配置檔案中的祕鑰


class IndexView(MethodView):  # cbv必須要繼承MethodView
    def get(self):
        url=url_for('aaa')  # 反向解析
        print(url)
        return '我是get'

    def post(self):
        return '我是post'

app.add_url_rule('/index',view_func=IndexView.as_view(name='aaa'))

if __name__ == '__main__':
    app.run(port=8888)

總結cbv原始碼

1.endpoint:如果傳了,優先使用endpoint,如果不傳使用as_view(name='aaa'),但是name='aaa'必須傳

2.cbv要繼承MethodView,只需要寫get函式,post函式...

3.cbv要繼承View,必須重寫dispatch,與django中cbv相同

6 模版

flask中的模板語法:

# flask中的模板語法:
	1.比django中多可以加括號,執行函式,傳引數
from flask import Flask,request,render_template,redirect,session,url_for,Markup
from flask.views import View,MethodView
app = Flask(__name__)

app.debug = True  # debug模式,開啟了,就會熱更新
app.secret_key = 'sdfsdfsdfsdf' # 祕鑰,django配置檔案中的祕鑰


def test(a,b):
    return a+b

class IndexView(MethodView):  # 繼承MethodView
    def get(self):
        url=url_for('aaa')   # 反向解析
        print(url)
        # html頁面顯示標籤
        # a=Markup('<a href="http://www.baidu.com">點我看美女</a>')
        a='<a href="http://www.baidu.com">點我看美女</a>'
        return render_template('test.html',name='lqz',test=test,a=a)

    def post(self):
        return '我是post'

if __name__ == '__main__':
    app.run(port=8888)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>{{name}}</h1>
<hr>
{{test(4,5)}}  // 呼叫函式並傳參
<hr>
{{a}}
{{a|safe}}  // 增加safe過濾器,顯示a標籤    
</body>
</html>

html頁面(執行函式並傳參)

image

html頁面(顯示a標籤)

image

總結

1. 跟dtl完全一樣,但是它可以執行函式
2. Markup等價django的mark_safe ,
3.extends,include一模一樣

相關文章