Flask基礎

Flask基礎

前言

  • django:1個重武器,包含 了web開發中經常使用的功能,組件的框架,
  • Tornado:2大特性就是異步非阻塞、原生支持WebSocke協議
  • Flask:封裝功能不及django完善、性能不及Tornado、可是擁有強大的第三方開源組件:http://flask.pocoo.org/extensions/
  • Flask是一個基於Python開發而且依賴jinja2模板和werkzeug WSGI服務的一個微型框架,對於Werkzeug本質是Socket服務端,其用於接收http請求並對請求進行預處理,而後觸發Flask框架,開發人員基於Flask框架提供的功能對其請求進行相應的處理,並返回給用戶,若是要返回給用戶複雜的內容時,須要藉助jinja2模板來實現對模板的處理,即:將模板和數據進行渲染,將渲染後的字符創返回給用戶瀏覽器。

安裝

爲了避免與現行項目想衝突,一般狀況下會引入一個虛擬環境,將Flask安裝在虛擬環境下,虛擬環境用virtualenvhtml

使用Virtualenv建立虛擬環境前端

img

將Flask安裝在該虛擬環境裏python

img

或者不配置直接web

pip install flask
#Flask依賴一個實現wsgi協議的模塊:werkzeug
from werkzeug.wrappers import Request, Response

@Request.application
def hello(request):
    return Response('Hello World!')

if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)

flask依賴於wsgi,實現wsgi模塊,wsgiref,werkzeug,uwsgi正則表達式

簡單使用

最簡使用

from flask import Flask

# 1 建立一個Flask實例
app = Flask(__name__)


@app.route('/')  # 路由系統生成,視圖對應url
def first_flask():  # 視圖函數
    return 'Hello World'


if __name__ == '__main__':
    app.run()  # 啓用socket

配置文件

  • flask初始化配置數據庫

    static_folder = 'static',  # 靜態文件目錄的路徑 默認當前項目中的static目錄
    static_host = None,  # 遠程靜態文件所用的Host地址,默認爲空
    static_url_path = None,  # 靜態文件目錄的url路徑 默認不寫是與static_folder同名,遠程靜態文件時複用
    # host_matching是否開啓host主機位匹配,是要與static_host一塊兒使用,若是配置了static_host, 則必須賦值爲True
    # 這裏要說明一下,@app.route("/",host="localhost:5000") 就必需要這樣寫
    # host="localhost:5000" 若是主機頭不是 localhost:5000 則沒法經過當前的路由
    host_matching = False,  # 若是不是特別須要的話,慎用,不然全部的route 都須要host=""的參數
    subdomain_matching = False,  # 理論上來講是用來限制SERVER_NAME子域名的,可是目前尚未感受出來區別在哪裏
    template_folder = 'templates'  # template模板目錄, 默認當前項目中的 templates 目錄
    instance_path = None,  # 指向另外一個Flask實例的路徑
    instance_relative_config = False  # 是否加載另外一個實例的配置
    root_path = None  # 主模塊所在的目錄的絕對路徑,默認項目目錄
  • 更改配置文件django

    app.config.from_object('settings.Base') # 更改配置文件
  • 經過路徑,找到類並獲取類中的靜態字段json

    FWQOF1.md.png

  • 配置文件flask

FWlLng.png

路由系統

@app.route('url地址',methods=['POST',"GET"],endpoint='別名',defaults={'nid':1},strict_slashes=True,redirect_to='/index') 
endpoint:反向生成url,默認是函數名 
endpoint= 至關於django中的name 
url_for 至關於 reverse 不定義默認是函數名
defaults:默認參數
strict_slashes:True 嚴格要求訪問的方式,
redirect_to='url':301重定向:永久重定向
  • 接收字符串類型後端

    from flask import Flask
    
    app=Flask(__name__)
    
    @app.route('/<name>')  #設置url傳參數 
    def first_flask(name):  #視圖必須有對應接收參數
        print(name)
        return 'Hello World'  #response
    
    
    if __name__ == '__main__':
        app.run()
  • 接收int,float,接收path連接類型

    # int類型
    @app.route('/<int:age>/')
    # float類型
    @app.route('/<float:salary>/') 
    # path類型
    @app.route('/<path:url>/')
    def first(url):   # 視圖必需要對應接收參數   
        pass
  • 指定容許的請求方法

    @app.route('/<path:url>/',methods=['get']) #只容許get請求
  • 經過別名反向生成url

    from flask import Flask,url_for
    app=Flask(__name__)
    @app.route('/<path:url>',endpoint='name1')  #設置別名
    def first_flask(url):
        print(url_for('name1',url=url)) #若是設置了url參數,url_for(別名,加參數)
        return 'Hello World'
    
    if __name__ == '__main__':
        app.run()

擴展:正則匹配url

from flask import Flask, views, url_for
            from werkzeug.routing import BaseConverter

            app = Flask(import_name=__name__)


            class RegexConverter(BaseConverter):
                """
                自定義URL匹配正則表達式
                """
                def __init__(self, map, regex):
                    super(RegexConverter, self).__init__(map)
                    self.regex = regex

                def to_python(self, value):
                    """
                    路由匹配時,匹配成功後傳遞給視圖函數中參數的值
                    :param value: 
                    :return: 
                    """
                    return int(value)

                def to_url(self, value):
                    """
                    使用url_for反向生成URL時,傳遞的參數通過該方法處理,返回的值用於生成URL中的參數
                    :param value: 
                    :return: 
                    """
                    val = super(RegexConverter, self).to_url(value)
                    return val

            # 添加到flask中
            app.url_map.converters['regex'] = RegexConverter


            @app.route('/index/<regex("\d+"):nid>')
            def index(nid):
                print(url_for('index', nid='888'))
                return 'Index'


            if __name__ == '__main__':
                app.run()
  • 路由與反向路由

視圖

  • FBV

    from flask import Flask,render_template
    app = Flask(__name__)
    # 導入配置
    app.config.from_object('settings.類名')
    
    @app.route('/')
    def index():
      return render_template('index.html')
    if __name__ == '__main__':
        app.run()
  • CBV (不經常使用)

    # 1.導入views
    from flask import views  
    # 寫一個類,與django中相似
    class User(views.methodView):
      methods = ['GET']
      decorators = ['裝飾器']
      def dispatch_request(self,*args,**kwargs):
          pass
        def get(self):
            self.dispatch_request()
            pass
        def post(self):
            pass
    # 加入app中
    app.add_url_rule('/user/', view_func=User.as_view(name='endpoint'))

    請求中request參數(經常使用)

    request.form   #存放form表單中的序列化數據
    request.args  # 存放url裏面的序列化數據
    request.values.to_dict() # 存放url和from中的全部數據
    request.method # 存放請求方式
    request.path   # 路由地址
    request.url  全部的url:所有地址
    request.host 主機位 127.0.0.1:5000
    request.host_url 將主機位轉換成url http://127.0.0.1:5000/
    request.data    查看傳過來全部解析不了的內容
    request.json  查看前端傳過來的json文件
    request.headers  查看全部的請求頭
    file = request.files  前端傳過來的文件
    file.filename 返回文件名稱
    file.save()  :保存文件

    響應相關

    return '字符竄'
    return render_template() # 返回一個頁面
    return redirect()  # 重定向
    return jsonify # 返回json數據,返回標準的json格式字符串 content-type: application/json

    模板渲染

    {{ }} 引用變量 非邏輯代碼時使用
    {% %} 邏輯代碼使用
    -基本數據類型,能夠執行python語法,如dict.get(),list[11]
    -傳入函數
        django,能夠執行
        flask,不自動執行
    -全局定義
        @app.template_global()
        @app.template_filter()
    -定義模板
        {% extends %} 引入模板
        {% include %} 引入一小部分
    -宏定義
        {% macro ccc(name,type='text',value='') %}
           <input type="{{ type }}" name={{ name }} value={{ value }}>
            <input type="button" value="提交">
         {% endmacro %}
    
         {{ ccc('name') }} 運行
    
    -安全
       -前端 {{ll|safe}}
       -後端 Markup('字符串')

    session

    # 1導入session
    from flask import session
    # 2須要對其進行加鹽,也能夠在配置文件中對其加鹽
    app.secret_key = 'alfkjs'
    # 3存session
    session['key'] = value
    # 4取值
    session.get('key', None)

flash(閃現)

  • 閃現,在session中存儲一個數據,讀取時經過pop將數據移出,

    flash('內容', category= 'ok')
    # 第一個存的內容
    # category 是別名,至關於分lei
    get_flashed_messages()  # 取全部
    # 獲取flash中的值,
    # get_flashed_messages()中的參數:
    with_categories=True  # True表示返回一個元祖
    category_filter='ok'  #取出別名爲ok的全部參數,放在一個列表中
    # 若是想將列表發送到前段,須要導入jsonify
  • 應用場景

    假設在A頁面作個操做,但該操做失敗了,要跳轉到B頁面並顯示這些錯誤信息

    from flask import Flask,flash,get_flashed_messages,request,redirect
    app = Flask(__name__)
    app.debug = True
    app.secret_key="1234"
    
    @app.route("/index")
    def index():
        # get請求用request.args.get, v是接受參數的變量
        # 瀏覽器請求:
        val = request.args.get('v')
        if val =="body":
            return "hello World, guys"
        # 若是請求參數不是body,則跳轉到錯誤頁面,須要將錯誤信息flash,也就是設置錯誤值到某個地方
        # A.flash不分類,直接設置值
        flash("前端輸入參數錯誤")
        # B.flash還能夠對錯誤信息,進行分類
        flash("前端輸入參數錯誤", category="x1")
        return redirect("/error")
    
    @app.route("/error")
    def error():
        '''
        顯示錯誤信息
        '''
        # 跳轉到error頁面後,請求時獲取錯誤信息
        # A.flash沒有分類時
        # data = get_flashed_messages()   # 獲取的就是flash的值
        # B. 對於有分類的,取值時能夠經過 category_filter 根據分類取錯誤信息
        data = get_flashed_messages(category_filter=['x1'])
        # 可能有不少的錯誤信息,也能夠按照索引的方式取出錯誤值
        if data:
            msg = data[0]
        else:
            msg = "..."
        return "錯誤信息:%s" %(msg)
    
    if __name__=="__main__":
        app.run()from flask import Flask,flash,get_flashed_messages,request,redirect
    app = Flask(__name__)
    app.debug = True
    app.secret_key="1234"
    
    @app.route("/index")
    def index():
        # get請求用request.args.get, v是接受參數的變量
        # 瀏覽器請求:
        val = request.args.get('v')
        if val =="body":
            return "hello World, guys"
        # 若是請求參數不是body,則跳轉到錯誤頁面,須要將錯誤信息flash,也就是設置錯誤值到某個地方
        # A.flash不分類,直接設置值
        flash("前端輸入參數錯誤")
        # B.flash還能夠對錯誤信息,進行分類
        flash("前端輸入參數錯誤", category="x1")
        return redirect("/error")
    
    @app.route("/error")
    def error():
        '''
        顯示錯誤信息
        '''
        # 跳轉到error頁面後,請求時獲取錯誤信息
        # A.flash沒有分類時
        # data = get_flashed_messages()   # 獲取的就是flash的值
        # B. 對於有分類的,取值時能夠經過 category_filter 根據分類取錯誤信息
        data = get_flashed_messages(category_filter=['x1'])
        # 可能有不少的錯誤信息,也能夠按照索引的方式取出錯誤值
        if data:
            msg = data[0]
        else:
            msg = "..."
        return "錯誤信息:%s" %(msg)
    
    if __name__=="__main__":
        app.run()

中間件

請求 執行前會執行一個wsgi_app,因此這裏就是重寫這個方法

from flask import Flask
app = Flask(__name__)

@app.route("/login", methods=['GET', 'POST'])
def index():
    pass

class Md(object):
    def __init__(self, old_wsgi_app):
        self.old_wsgi_app = old_wsgi_app

    def __call__(self, environ, start_response):
        print("開始以前")
        ret = self.old_wsgi_app(environ, start_response)
        print("結束以後")
        return ret

if __name__ =="__main__":
    app.wsgi_app = Md(app.wsgi_app) # 至關於把wsgi_app給更新了
    app.run()

藍圖

  • 藍圖的做用,就是將功能和主服務分開.

  • 簡單理解就是用藍圖實例化一個對象,而後由這個對象寫一個函數,再加入flask中

  • 使用藍圖的目標:

    \1. 構造程序目錄

    \2. 自定義程序目錄

      批量處理url

      定製模板路徑和靜態文件路徑

      請求擴展:

        - 能夠針對app, 即所有程序都生效

        - 也能夠針對單個的藍圖,即只有在執行該藍圖時,請求擴展才會生效

簡單實例:

  • 目錄結構

    img

  • s_view.py中內容

    from flask import Blueprint  # 導入 Flask 中的藍圖 Blueprint 模塊
    
    sv = Blueprint("sv", __name__)  # 實例化一個藍圖(Blueprint)對象
    
    
    @sv.route("/svlist")  # 這裏添加路由和視圖函數的時候與在Flask對象中添加是同樣的
    def view_list():
        return "svlist_view_list"
  • manager.py中的內容

    from flask import Flask
    
    # 導入此前寫好的藍圖模塊
    from student_view import s_view
    
    app = Flask(__name__)  # type:Flask
    
    # 在Flask對象中註冊藍圖模塊中的藍圖對象 s_view 中的 sv
    app.register_blueprint(s_view.sv)
    
    app.run("0.0.0.0",5000)
    # 如今Flask對象中並無寫任何的路由和視圖函數

    而後開啓服務,就能夠訪問了http://127.0.0.1:5000/svlist

  • 詳情:請查看博客: https://www.cnblogs.com/95lyj/p/9509229.html

特殊的裝飾器

@app.template_global() 全局函數
@app.template_filter() 相似標籤

@app.before_request     相似於process_request:沒有參數 順序:從上到下
@app.after_request      相似於process_response:必須有參數,並返回 順序:從下到上:即便在第一個就返回,也會所有執行一遍
@app.before_first_request  只有第一次執行
@app.teardown_request    在有異常發生時觸發

@app.errorhandler(404)  沒找到頁面走這個之下的函數,有一個參數

@app.before_request 用來作認證模塊

@app.before_request
def process_request(*args, **kwargs):
    # 驗證表示,任何地址請求都會先執行before_request,因此登陸驗證就能夠在before_request裏作用戶認證功能了
    print("其餘請求以前就執行了process_request")
    # 4.訪問/login的時候尚未登陸,就會一直重定向到登陸頁,因此就要設置個白名單,若是請求地址是/login,就返回None
    if request.path == "/login":
        return None
    # 1.登陸驗證功能
    user = session.get('user_info')
    # 2.若是登陸信息正常,什麼都不作,程序繼續其餘執行
    if user:
        return None
    # 3.若是登陸驗證不經過,就重定向到登陸頁面
    return redirect("/login")

@app.after_request after_first_request

在請求進入視圖函數以前執行,與他做用相同的@app.before_first_request也是,不一樣點是這個只執行一次,而after_request能夠執行屢次,按照順序執行

@app.after_request
def foot_log(environ):
    if request.path != "/login":
        print("有客人訪問了",request.path)
    return environ

注意:

可是要注意,多個請求擴展的執行順序是有差異的:
對於before_request,是按照寫的代碼的順序從上到下的順序正序執行的
對於after_request, 是按照寫的代碼的順序從下到上的順序倒序執行的

若是before_request return了(即程序被攔截了),其餘before_request就不執行了,可是全部的after_request都會繼續執行

實例

from flask import Flask,render_template,request,redirect,session,url_for
app = Flask(__name__)
app.debug = True
app.secret_key = 'siuljskdjfs'

@app.before_request
def process_request1(*args,**kwargs):
    print('process_request1 進來了')
    return "攔截"

@app.before_request
def process_request2(*args,**kwargs):
    print('process_request2 進來了')

@app.after_request
def process_response1(response):
    print('process_response1 走了')
    # after_request 必須返回 response
    return response

@app.after_request
def process_response2(response):
    print('process_response2 走了')
    return response

# 視圖函數
@app.route('/index',methods=['GET'])
def index():
    print('index函數')
    return "Index"


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

執行結果:

img

errorhandler(404) 定製錯誤信息

from flask import Flask,render_template,request,redirect,session,url_for
app = Flask(__name__)
app.debug = True
app.secret_key = 'siuljskdjfs'

# 常常會出現url不存在的狀況,通常會有錯誤信息
# 而這個錯誤信息也是能夠進行定製的,根據錯誤碼定製錯誤信息方法以下:
@app.errorhandler(404)
def error_404(arg):
    return "404錯誤了"

# 視圖函數
@app.route('/index',methods=['GET'])
def index():
    print('index函數')
    return "Index"

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

模板中定製方法(定製模板方法): template_global() 和 template_filter()

from flask import Flask,request
app = Flask(__name__)
app.debug = True

# 這就是基於請求擴展的 定製模板方法
# 相對於在模板裏定製了一個函數

@app.template_global()
def sb(a1, a2):
    return a1 + a2

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


#在HTML裏調用的方式以下:
{{sb(1,2)}}
from flask import Flask,request
app = Flask(__name__)
app.debug = True

# 這就是基於請求擴展的 定製模板方法
@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3

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

#在HTML裏調用的方式以下:
 {{ 1|db(2,3)}   # 參數 a1 = 1,是第一個參數; a2=2 是第二個參數;   a3=3 是第三個參數

before_first_request

  • 應用場景:數據庫的鏈接,初始化操做

    from flask import Flask,request
    app = Flask(__name__)
    app.debug = True
    
    # 內部其實就有個判斷,初始值是FALSE,第一次執行後將值改變爲True,之後判斷後就不執行了
    @app.before_first_request
    def before_first_request2():
        print('before_first_request2')
    
    if __name__ == '__main__':
        app.run()
相關文章
相關標籤/搜索