1. 程式人生 > 實用技巧 >flask - 進階

flask - 進階

flask 進階

上下文管理和SQLHelper

```python
import pymysql
from DBUtils.PooledDB import PooledDB

class SqlHelper(object):
    def __init__(self):
        self.pool = PooledDB(
            creator=pymysql,  # 使用連結資料庫的模組
            maxconnections=6,  # 連線池允許的最大連線數,0和None表示不限制連線數
            mincached=2,  # 初始化時,連結池中至少建立的連結,0表示不建立
            blocking=True,  # 連線池中如果沒有可用連線後,是否阻塞等待。True,等待;False,不等待然後報錯
            ping=0,
            # ping MySQL服務端,檢查是否服務可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = always
            host='127.0.0.1',
            port=3306,
            user='root',
            password='222',
            database='cmdb',
            charset='utf8'
        )

    def open(self):
        conn = self.pool.connection()
        cursor = conn.cursor()
        return conn,cursor

    def close(self,cursor,conn):
        cursor.close()
        conn.close()

    def fetchall(self,sql, *args):
        """ 獲取所有資料 """
        conn,cursor = self.open()
        cursor.execute(sql, args)
        result = cursor.fetchall()
        self.close(conn,cursor)
        return result

    def fetchone(self,sql, *args):
        """ 獲取所有資料 """
        conn, cursor = self.open()
        cursor.execute(sql, args)
        result = cursor.fetchone()
        self.close(conn, cursor)
        return result

    def __enter__(self):
        return self.open()[1]

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(exc_type, exc_val, exc_tb)


db = SqlHelper()
```

概要

  • wsgi
  • 建立flask物件
    • 模板
    • 靜態檔案
  • 路由系統
    • 路由的應用:裝飾器(推薦)、方法
    • 動態路由
  • 檢視
    • FBV
    • CBV
  • 模板
    • 繼承
    • include
    • 自定義標籤
  • 特殊裝飾器
    • before_request充當中介軟體角色

詳細

1.wsgi 找原始碼的流程

from werkzeug.serving import run_simple
from werkzeug.wrappers import BaseResponse

def func(environ, start_response):
    print('請求來了')
    response = BaseResponse('你好')
    return response(environ, start_response)


if __name__ == '__main__':
    run_simple('127.0.0.1', 5000, func)
"""
    1.程式啟動,等待使用者請求到來
        app.run()
    2.使用者請求到來 app()    
        app.__call__
"""

from flask import Flask

app = Flask(__name__)

@app.route('/index')
def index():
    return 'hello world'

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

2.flask物件

靜態檔案的處理。

推薦

from flask import Flask,render_template

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

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

if __name__ == '__main__':
    app.run()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>首頁</h1>
    <img src="/static/xx/xx/mm.jpg" />
    
    <!-- 建議 -->
    <img src="{{ url_for('static',filename='xx/xx/mm.jpg')}}" />
</body>
</html>

3.配置檔案

3.1 基於全域性變數

3.2 基於類的方式

4.路由系統

  • 路由的兩種寫法

    def index():
        return render_template('index.html')
    app.add_url_rule('/index', 'index', index)
    
    
    # 公司裡一般用這種方式
    @app.route('/login')
    def login():
        return render_template('login.html')
    
  • 路由載入的原始碼流程

    - 將url和函式打包成為 rule 物件
    - 將rule物件新增到map物件中。
    - app.url_map = map物件
    
  • 動態路由

    @app.route('/login')
    def login():
        return render_template('login.html')
        
    @app.route('/login/<name>')
    def login(name):
    	print(type(name))
        return render_template('login.html')
        
    @app.route('/login/<int:name>')
    def login(name):
    	print(type(name))
        return render_template('login.html')
    
  • 支援正則表示式的路由

    from flask import Flask,render_template
    
    app = Flask(__name__)
    
    
    from werkzeug.routing import BaseConverter
    class RegConverter(BaseConverter):
        def __init__(self, map, regex):
            super().__init__(map)
            self.regex = regex
    app.url_map.converters['regex'] = RegConverter
    
    @app.route('/index/<regex("\d+"):x1>')
    def index(x1):
        return render_template('index.html')
    
    if __name__ == '__main__':
        app.run()
    

5.檢視

5.1 FBV

def index():
    return render_template('index.html')
app.add_url_rule('/index', 'index', index)


# 公司裡一般用這種方式
@app.route('/login')
def login():
    return render_template('login.html')

5.2 CBV

from flask import Flask,render_template,views

app = Flask(__name__,)

def test1(func):
    def inner(*args,**kwargs):
        print('before1')
        result = func(*args,**kwargs)
        print('after1')
        return result
    return inner

def test2(func):
    def inner(*args,**kwargs):
        print('before2')
        result = func(*args,**kwargs)
        print('after2')
        return result
    return inner


class UserView(views.MethodView):
    methods = ['GET',"POST"]

    decorators = [test1,test2]   #裝飾器傳


    def get(self):
        print('get')
        return 'get'

    def post(self):
        print('post')
        return 'post'

app.add_url_rule('/user', view_func=UserView.as_view('user')) # endpoint  反向生成

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

6.模板

6.1 基本用法

flask比django更加接近Python。

from flask import Flask,render_template

app = Flask(__name__,)

def func(arg):
    return '你好' + arg

@app.route('/md')
def index():
    nums = [11,222,33]
    return render_template('md.html',nums=nums,f=func)


if __name__ == '__main__':
    app.run()
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>頭</h1>
        {% block content %} {% endblock %}
    <h1>底</h1>
</body>
</html>
<form action="">
    <input type="text">
    <input type="text">
    <input type="text">
    <input type="text">
    <input type="text">
</form>
{% extends 'layout.html' %}


{% block content %}
    <h1>MD</h1>
    {% include 'form.html' %}
    {{ f("汪洋") }}
{% endblock %}

6.2 定義全域性模板方法

from flask import Flask,render_template

app = Flask(__name__,)

@app.template_global() #  {{ func("趙海宇") }}
def func(arg):
    return '海狗子' + arg

@app.template_filter() # {{ "趙海宇"|x1("孫宇") }}
def x1(arg,name):
    return '海狗子' + arg + name


@app.route('/md/hg')
def index():
    return render_template('md_hg.html')

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

注意:在藍圖中註冊時候,應用返回只有本藍圖。

7.特殊裝飾器

from flask import Flask,render_template,request

app = Flask(__name__)

@app.before_request
def f1():
    if request.path == '/login':
        return
    print('f1')
    # return '123'

@app.after_request
def f10(response):
    print('f10')
    return response

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

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

多個裝飾器

from flask import Flask,render_template,request

app = Flask(__name__)

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

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

@app.after_request
def f10(response):
    print('f10')
    return response

@app.after_request
def f20(response):
    print('f20')
    return response

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

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

注意:before_after request可以在藍圖中定義,在藍圖中定義的話,作用域只在本藍圖。

8.小細節

from flask import Flask,render_template

app = Flask(__name__,)

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


@app.before_request
def func():
    print('xxx')

def x1():
    print('xxx')
app.before_request(x1)

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

:threading.local

import time
import threading

# 當每個執行緒在執行 val1.xx=1 ,在內部會為此執行緒開闢一個空間,來儲存 xx=1
# val1.xx,找到此執行緒自己的記憶體地址去取自己儲存 xx
val1 = threading.local()

def task(i):
    val1.num = i
    time.sleep(1)
    print(val1.num)

for i in range(4):
    t = threading.Thread(target=task,args=(i,))
    t.start()