flask基礎

1、簡介

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

  本篇文章將對比與django介紹flask的基本組件以及相關使用方法。前端

Flask與Django對比:
  • Django功能大而全,Flask只包含基本的配置 Django的一站式解決的思路,能讓開發者不用在開發以前就在選擇應用的基礎設施上花費大量時間。Django有模板,表單,路由,認證,基本的數據庫管理等等內建功能。與之相反,Flask只是一個內核,默認依賴於兩個外部庫: Jinja2 模板引擎和 Werkzeug WSGI 工具集,其餘不少功能都是以擴展的形式進行嵌入使用。
  • Flask 比 Django 更靈活 用Flask來構建應用以前,選擇組件的時候會給開發者帶來更多的靈活性 ,可能有的應用場景不適合使用一個標準的ORM(Object-Relational Mapping 對象關聯映射),或者須要與不一樣的工做流和模板系統交互。
  • 組件對比:

    django:無socket、依賴第三方模塊wsgi、中間件、路由系統、視圖、ORM、cookie、session、Admin、Form、緩存、信號、序列化。python

    Flask:  無socket、中間件(擴展)、路由系統、視圖(第三方模塊,依賴jinja2)、cookie、session。mysql

 

2、快速開始

安裝

pip3 install flask

簡單使用

#!/usr/bin/env python3
#_*_ coding:utf-8 _*_
#Author:wd

from flask import Flask
app = Flask(__name__) # 實例化Flask對象

@app.route('/') #添加路由
def hello_world():
return 'Hello World!' # 返回

if __name__ == '__main__':
app.run() # 運行服務器

3、配置處理

配置方式

flask的配置文件是經過Flask對象的config.Configs進行配置,本質是字典其中配置文件有如下實現方式:正則表達式

方式一:
    app.config['DEBUG'] = True
   # PS: 因爲Config對象本質上是字典,因此還可使用app.config.update(...)
方式二:
    app.config.from_pyfile("python文件名稱")
        如:
            settings.py
                DEBUG = True
            app.config.from_pyfile("settings.py")
    app.config.from_envvar("環境變量名稱")#環境變量的值爲python文件名稱名稱,內部調用from_pyfile方法
    app.config.from_json("json文件名稱")  #JSON文件名稱,必須是json格式,由於內部會執行json.loads
    app.config.from_mapping({'DEBUG':True})   ###字典格式
    app.config.from_object("python類或類的路徑」)  ###推薦
        ###示例:
        app.config.from_object('pro_flask.settings.TestingConfig')
        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
        #PS: 從sys.path中已經存在路徑開始寫
#更多配置參數參考:http://flask.pocoo.org/docs/1.0/config/#builtin-configuration-values
     

4、路由系統

  flask的路由系統可能區別與django之一在於其路由的實現是由裝飾器完成的。sql

使用方式

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd
from flask import Flask
app=Flask(__name__)

#####方式一,裝飾器方式,endpoint至關於別名,用於反向生成url

@app.route(rule='/index',endpoint='a1')  
def index():
    return 'index'

def index1(): 
    return 'index1'

####方式二,使用函數方式

app.add_url_rule(rule='/index1',endpoint='a2',view_func=index1)   

經常使用參數數據庫

  • rule                            URL規則
  • view_func                  視圖函數名稱
  • defaults=None            默認值,當URL中無參數,函數須要參數時,使用defaults={'k':'v'}爲函數提供參數
  • endpoint=None     url別名,用於反向生成URL,即: url_for(‘別名’)
  • methods=None           容許的請求方式,如:methods=["GET","POST"]
  • strict_slashes=None    對URL最後的 / 符號是否嚴格要求,默認嚴格,設置爲False即最後帶/或不帶都能匹配
  • redirect_to=None        重定向到指定新地址如:redirect_to='/<user>/login’,當跳轉的url有參數時候,也須要加上參數

路由規則

  經過把 URL 的一部分標記爲 <variable_name> 就能夠在 URL 中添加變量。標記的 部分會做爲關鍵字參數傳遞給函數。經過使用 <converter:variable_name> ,能夠 選擇性的加上一個轉換器,爲變量指定規則。django

 

@app.route('/user/<username>')  # 普通規則,username至關於變量,在url中指定例如/user/wd,username就是wd
def show_user_profile(username):
    return 'User %s' % username


@app.route('/post/<int:post_id>')  # 整型轉換器,post後面只能是int類型,不然404
def show_post(post_id):
    return 'Post %d' % post_id


@app.route('/path/<path:subpath>')  # 路徑轉換器
def show_subpath(subpath):
    return 'Subpath %s' % subpath

內置轉換器json

DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,  #默認數據類型,但不包含斜槓的文本
    'string':           UnicodeConverter,  #默認數據類型
    'any':              AnyConverter,      #多個路徑
    'path':             PathConverter,     #相似字符串,能夠包含斜槓
    'int':              IntegerConverter,  #只能是int類型
    'float':            FloatConverter,    #只能是float類型
    'uuid':             UUIDConverter,     #只能是uuid字符串
}

URL反向生成

  在django中咱們能夠經過reverse方法反向生成url,一樣在flask也能夠經過url_for反向生成。flask

# -*- coding:utf-8 -*-
# Author:wd
from flask import Flask,url_for

app = Flask(__name__)


@app.route('/user/<username>',endpoint='a1') 
def show_user_profile(username):
    print(url_for('a1',username='jack', next='/'))  #可根據須要傳遞參數,第一個參數是視圖函數或者endpoint,第二個參數是須要傳遞的參數,next根據需求
    print(url_for('a1', username='jack'))
    return 'User %s' % username


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

#結果
#/user/jack?next=%2F
#/user/jack

自定義URL規則

擴展本身的自定義URL規則須要繼承BaseConverter,重寫to_url方法。

from flask import Flask,url_for

    app = Flask(__name__)

    # 定義轉換的類
    from werkzeug.routing import BaseConverter
    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

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

    # 進行使用
    @app.route('/index/<regex("\d+"):nid>',endpoint='xx')
    def index(nid):
        url_for('xx',nid=123)  #反向生成,就會去執行to_url方法
        return "Index"

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

5、視圖

CBV和FBV

在django中視圖分爲CBV和FBV,固然Flask視圖也分CBV和FBV

FBV

###方式一:
    @app.route('/index',endpoint=‘a1')
    def index(nid):
        return "Index"

###方式二:
    def index(nid):
        return "Index"

    app.add_url_rule('/index',index)

CBV

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd
from flask import url_for, views, Flask

app = Flask(__name__)


def auth(func):  # 裝飾器
    def inner(*args, **kwargs):
        print('require auth')
        result = func(*args, **kwargs)
        return result

    return inner


class IndexView(views.MethodView):
    methods = ['GET', 'POST']  # 只容許GET、POST請求訪問
    decorators = [auth, ]  # 若是想給全部的get,post請求加裝飾器,就能夠這樣來寫,也能夠單個指定

    def get(self):  # 若是是get請求須要執行的代碼
        v = url_for('index')
        print(v)
        return "GET"

    def post(self):  # 若是是post請求執行的代碼
        return "POST"


app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name指定的是別名,會當作endpoint使用

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

使用裝飾器

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd
from flask import url_for, views, Flask

app = Flask(__name__)

def auth(func):  # 裝飾器
    def inner(*args, **kwargs):
        print('require auth')
        result = func(*args, **kwargs)
        return result

    return inner


####FBV裝飾器
@app.route(‘/login', methods=['GET', 'POST'])
@auth  # 注意若是要給視圖函數加裝飾器,一點要加在路由裝飾器下面,纔會被路由裝飾器裝飾
def login():
    return 'login'


class IndexView(views.MethodView):
    methods = ['GET', 'POST']  # 只容許GET、POST請求訪問
    ####CBV裝飾器
    decorators = [auth, ]  # 若是想給全部的get,post請求加裝飾器,就能夠這樣來寫,也能夠單個指定

    def get(self):  # 若是是get請求須要執行的代碼
        v = url_for('index')
        print(v)
        return "GET"

    def post(self):  # 若是是post請求執行的代碼
        return "POST"


app.add_url_rule('/index', view_func=IndexView.as_view(name='index'))  # name指定的是別名,會當作endpoint使用

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

6、請求與響應

  在django中經過request獲取請求信息經過render、httpresponse等響應數據,一樣在flask中也是經過request來獲取請求數據,requset須要導入。

請求相關

#導入 from flask import request

####請求相關信息 
request.method:獲取請求方法
request.json.get("json_key"):獲取json數據 **較經常使用      

request.argsget('name') :獲取get請求參數   

request.form.get('name') :獲取POST表單請求參數

request.form.getlist('name_list'):獲取POST表單請求參數列表(如多選)

request.values.get('age') :獲取GET和POST請求攜帶的全部參數(GET/POST通用)

request.cookies.get('name'):獲取cookies信息

request.headers.get('Host'):獲取請求頭相關信息

request.path:獲取用戶訪問的url地址,例如(/,/login/,/ index/);

request.full_path:獲取用戶訪問的完整url地址+參數 例如(/login/?name=wd)

request.url:獲取訪問url地址,例如http://127.0.0.1:5000/?name=18

request.base_url:獲取訪問url地址,例如 http://127.0.0.1:5000/;

request.url_root:不帶參數的根url,例如  http://127.0.0.1:5000/;

request.host_url:不帶參數的根host,當使用ip方式訪問的時候同url_root例如  http://127.0.0.1:5000/;

request.host:獲取主機地址

request.files:獲取用戶上傳的文件

obj = request.files['the_file_name']

obj.save('/var/www/uploads/' + secure_filename(f.filename))  直接保存文件

響應相關

################基本響應類型

return "字符串" :響應字符串

return render_template('html模板路徑',**{}):響應模板

return redirect('/index.html'):跳轉頁面

##############JSON格式響應

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd
from flask import url_for, views, Flask, request, Response
import json
app = Flask(__name__)

@app.route('/login', methods=['GET', 'POST'])
def login():
    response = Response(json.dumps({"status":"ok"}), mimetype="application/json;charset=utf-8")
    return response

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

##################設置響應信息

#導入
from flask import make_response

response = make_response(render_template('index.html’))  #也能夠相應模版

response.delete_cookie('key’)             #刪除cookie中的一個key 

response.set_cookie('key', 'value’)      #設置cookie

response.headers['username'] = ‘wd’  #設置響應頭信息

return response

7、模版

flask的模版引擎和django同樣都採用Jinja2(參考:http://jinja.pocoo.org/docs/2.10/templates/)

獲取單個數據

{{ key }} 

for循環

{% for item in item_list %} 
<a>{{ item }}</a> 
{% endfor %}

demo:

<html>
     <body>
          <!-- 列表循環 -->
          {% for i in k1 % }
               <h1>{{ i }}</h1>
          {% endfor % }

          <!-- 字典循環 -->
          {% for k in k2.keys % }
               <h1>{{ k }}</h1>
          {% endfor % }
          
          {% for v in k2.values % }
               <h1>{{ v }}</h1>
          {% endfor % }
          
          {% for k,v in k2.items % }
               <h1>{{ k }}-{{ v }}</h1>
          {% endfor % }
     </body>
</html>

判斷

{% if ordered_warranty %}  {% else %} {% endif %}

模版繼承(extends)

母模版:
{% block name %}
{% endblock %}

使用:
先聲明:
{% extends 'html模版' %}
{% block name %}
{% endblock %}

當某個元素屢次使用時候,咱們能夠定義宏

{% macro input(name, type='text', value='') %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

{{ input('n1') }}

解除XSS

若是防止HTML顯示爲字符串,flask採用Markup實現,而django採用make_safe。

###後端
return Markup("<input type='text' value='wd'>")

###前端

{{"<input type='text'>"|safe}}

過濾器

Flask的Jinjia2能夠經過Context 把視圖中的函數傳遞把模板語言中執行,這就是Django中的simple_tag和simple_fifter功能。

simple_tag(只能傳2個參數,支持for、if)

#!/usr/bin/env python3
#_*_ coding:utf-8 _*_
#Author:wd

from flask import Flask,render_template
app = Flask(__name__)
@app.route('/index')
def index():
return render_template('index.html')


@app.template_global() #simple_tag
def foo(arg):
return "<input type='text' value='{}'>".format(arg)

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

index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>{{foo('wd')|safe }}</div>
</body>
</html>

simple_fifter(對參數個數無限制,不支持for、if)

#!/usr/bin/env python3
#_*_ coding:utf-8 _*_
#Author:wd

from flask import Flask,render_template,Markup
app = Flask(__name__)

@app.route('/login')
def login():
return render_template('login.html')


@app.template_filter() #simple_fifter
def bar(arg1,arg2,arg3):
return Markup("<input type='text' value='{}'>".format(arg1+arg2+arg3))

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

login.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>{{ 'wd'|bar('name','is ')}}</div>
</body>
</html>

8、session

  除請求對象以外,還有一個 session 對象,本質上來講就是一個字典。它容許你在不一樣請求間存儲特定用戶的信息。它是在 Cookies 的基礎上實現的,而且對 Cookies 進行密鑰簽名要使用會話,須要設置一個密鑰。

相關操做

#設置session:session[‘username'] = ‘wd’
#刪除session:del session[‘username’]或者session.pop(‘username’)
#清空session:session.clear()

簡單的登陸驗證demo:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd
from flask import session, Flask, request, redirect, render_template

app = Flask(__name__)
app.secret_key = 'adsadq2dq'  # 設置加密的鹽
app.config['SESSION_COOKIE_NAME'] = 'session_wd'  # 設置session的名字


def auth(func):   # 登陸認證裝飾器
    def inner(*args, **kwargs):
        if not session.get('username'): return redirect('/login')
        return func(*args, **kwargs)
    return inner


@app.route('/index', methods=['GET', 'POST'])
@auth
def index():
    return render_template('index.html')


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == "GET":
        return render_template('login.html')
    if request.form.get('username') == 'wd' and request.form.get('password') == '123':
        session['username'] = 'wd'
        return redirect('/index')


@app.route('/logout')
def logout():
    session.clear()

    return redirect('/login')


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

session配置

配置方法在以前已經提到,如 app.config['SESSION_COOKIE_NAME'] = 'session_wd'

            'SESSION_COOKIE_NAME':                  'session’, # session 名稱配置
            'SESSION_COOKIE_DOMAIN':                None,
            'SESSION_COOKIE_PATH':                  None,
            'SESSION_COOKIE_HTTPONLY':              True,
            'SESSION_COOKIE_SECURE':                False,
            'SESSION_REFRESH_EACH_REQUEST':         True,  #是否每次都跟新
            'PERMANENT_SESSION_LIFETIME':           timedelta(days=31)  #設置seesion超時時間

9、 blueprint(藍圖)

  正如上面介紹,flask簡便易用,一個py文件就能夠完成一個小項目,當項目相對大時候,咱們就須要將目錄進行結構劃分,藍圖的功能就在於此。

使用

目錄結果

monitor                #項目主目錄
├── __init__.py
├── runserver.py       #啓動腳本
├── statics            #靜態文件
├── templates          #模版目錄
└── views              #視圖目錄
    ├── account.py
    └── permission.py

各個py文件:

from flask import Flask
from .views import account
from .views import permission

app = Flask(__name__, template_folder='templates', static_folder='statics', static_url_path='/static')
app.register_blueprint(blueprint=account.login_bp,url_prefix='/account’)   #註冊一個藍圖
app.register_blueprint(blueprint=permission.permit_bp, url_prefix='/permit')
monitor/__init__.py
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd

from flask import Blueprint


login_bp=Blueprint('login',__name__)    #實例化一個藍圖

@login_bp.route('/login',methods=['GET','POST'])
def login():
    return '登陸頁'
views/account.py
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd

from monitor import app

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

10、消息閃現(flash)

  Flask 的閃現系統提供了一個良好的反饋方式。閃現系統的基 本工做方式是:在且只在下一個請求中訪問上一個請求結束時記錄的消息。通常咱們結合佈局模板來使用閃現系統。消息閃現原理是flask的 session組件而該組件是基於cookie的,瀏覽器會限制 cookie 的大小,有時候網絡服 務器也會。這樣若是消息比會話 cookie 大的話,那麼會致使消息閃現靜默失敗。

特色:一次性,使用一次就刪除。
應用場景之一:數據驗證返回錯誤信息。
示例:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd


from flask import Flask, flash, get_flashed_messages, request, render_template, redirect, url_for

app = Flask(__name__)
app.secret_key = '123addqe1'


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == "POST":
        if request.form.get('username') == 'wd' and request.form.get('password') == '123':
            flash(message='wd')  # 設置消息
            return redirect(url_for('index'))
        else:
            flash(message='用戶名或者密碼錯誤')

    return render_template('login.html')


@app.route('/index', methods=['GET', 'POST'], endpoint='index')
def index():
    messge = get_flashed_messages()  # 獲取消息
    return 'ok username {}'.format(''.join(messge))


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

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form method="post">
    <div><input type="text" name="username"></div>
    <div><input type="password" name="password"></div>
    <div><input type="submit" name="password"></div>
    <div>
        {% with messages = get_flashed_messages() %}
            {% if messages %}
            <ul class=flashes>
                {% for message in messages %}
                <li>{{ message }}</li>
                {% endfor %}
            </ul>
            {% endif %}
        {% endwith %}
    </div>
</form>
</body>
</html>

消息分類

  閃現消息還能夠指定類別,若是沒有指定,那麼缺省的類別爲 'message' 。不一樣的類別能夠給用戶提供更好的反饋,獲取改級別的時候須要加參數with_categories=True。例如錯誤消息能夠error,此時的消息是一個tuple。

示例:

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == "POST":
        if request.form.get('username') == 'wd' and request.form.get('password') == '123':
            flash(message='wd')  # 設置消息
            return redirect(url_for('index'))
        else:
            flash(message='用戶名或者密碼錯誤',category='ERROR')
            print(get_flashed_messages(with_categories=True))   # 結果[('ERROR', '用戶名或者密碼錯誤')]
    return render_template('login.html')

消息過濾

  若是想獲得某個指定類別或者多個類別的消息則在獲取的時候使用參數category_filter

messge = get_flashed_messages(category_filter=["ERROR",])  # 獲取指定類型的消息

11、請求擴展(內置請求鉤子)

  flask的請求鉤子是經過裝飾器實現的,經過這些鉤子函數咱們能夠在請求的每一個階段執行本身的業務邏輯。

如下是經常使用請求擴展裝飾器:

  • @app.before_first_request :請求第1次到來執行1次,以後都不執行;
  • @app.before_request:請求到達視圖以前執行,若是此函數有返回值則直接返回(不執行視圖函數),若是此方法定義了多個則最上面的開始執行;
  • @app.after_request:請求通過視圖以後執行,若是改方法從上到下定義了多個,則最下面的先執行;
  • @app.errorhandler: 請求錯誤時候的處理,error_code表明http狀態碼; 
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# Author:wd
from flask import Flask, Request, render_template

app = Flask(__name__, template_folder='templates')



@app.before_first_request  # 第1個請求到來執行
def before_first_request1():
    print('before_first_request1')


@app.before_request  # 中間件2
def before_request1():
    Request.nnn = 123
    print('before_request1')  # 不能有返回值,一旦有返回值在當前返回


@app.before_request
def before_request2():
    print('before_request2')

@app.errorhandler(404)  # 404錯誤處理
def page_not_found(error):
    return 'This page does not exist', 404


@app.route('/')
def index():
    return "Index"


@app.after_request  # 中間件 執行視圖以後
def after_request1(response):
    print('after_request1', response)
    return response


@app.after_request  # 中間件 執行視圖以後 先執行 after_request2
def after_request2(response):
    print('after_request2', response)
    return response


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


#結果:
#before_request1 #before_request2 #after_request2 <Response 5 bytes [200 OK]> #after_request1 <Response 5 bytes [200 OK]>
相關文章
相關標籤/搜索