flask模板語言,裝飾器,路由及配置

1.模板語言jinja2

  Flask中默認的模板語言是Jinja2

1.0 模板傳參

from flask import Flask,render_template

app = Flask(__name__)

@app.route("/")
def index():
    content = {
        "name":"learning",
        "age":"18",
        "sex":""
    }
    return render_template("index.html",**content)

if __name__ == "__main__":
    app.run(port=5225,debug=True)

index.html

<div>
    {{ name }}
    {{ age }}
    {{ sex }}
</div>

效果

1.1 從後端傳HTML標籤

# 常規做法,前端引入safe

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ tags|safe }}
</body>
</html>

app.py

from flask import Flask,render_template

app = Flask(__name__)


@app.route("/")
def index():
    tags = "<input type='text' name='user' value='輸入'>"
    return render_template("login.html",tags=tags)

if __name__ == "__main__":
    app.run(port=5225,debug=True)

# 引入Markup,它的作用在HTML的標籤上做一層封裝,讓Jinja2模板語言知道這是一個安全的HTML標籤

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ tags }}
</body>
</html>

app.py

from flask import Flask,render_template,Markup

app = Flask(__name__)

@app.route("/")
def index():
    tags = "<input type='text' name='user' value='輸入'>"
    markup = Markup(tags)
    return render_template("login.html",tags=markup)

if __name__ == "__main__":
    app.run(port=5225,debug=True)

1.2 模板內執行函數

app.py

from flask import Flask,render_template,Markup

app = Flask(__name__)

# 定義一個函數
def sums(a,b):
    return a+b

@app.route("/")
def index():
    return render_template("login.html",tags=sums)

if __name__ == "__main__":
    app.run(port=5225,debug=True)

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ tags }}
    <div>{{ tags(38,37) }}</div>
</body>
</html>

效果:

1.3 flask中的裝飾器

from flask import Flask,request,redirect,render_template,session
app = Flask(__name__)
app.secret_key = "123"  # 開啓session功能的時候必須添加該配置secret_key
# 模擬數據
STUDENT_DICT = {
    1: {'name': '呂洋'},
    2: {'name': '黃曉'},
    3: {'name': '餘燼'},
}

@app.route("/login",methods=["GET","POST"])
def login():
    if request.method =="GET":
        return render_template("login.html")

    if request.method == "POST":
        username = request.form.get("username")
        password = request.form.get("password")
        if username =="bob" and password == "123":
            session["user"] = username
            return redirect("/index")
        else:
            return render_template("login.html", msg="用戶名密碼錯誤")


@app.route("/index")
def index():
    if session.get("user"):
        return render_template("index.html",stu=STUDENT_DICT)
    return redirect("/login")


if __name__ == "__main__":
    app.run(port=5225,debug=True)

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
   <table border="1px">
       <tr>
           <th>id</th>
           <th>name</th>
           <th>option</th>
       </tr>
       <tr>
           {% for k,v in stu.items() %}
           <td>{{ k }}</td>
           <td>{{ v.name }}</td>
           <td><a href="/detail?id={{ k }}">詳細</a>|<a href="/delete/{{ k }}">刪除</a></td>
       </tr>
       {% endfor %}
   </table>
</body>
</html>

 # 用戶必須先登錄,才能訪問index

 效果:

說明:

  html模板渲染一般都存放在項目主目錄下的templates下,否則會出現一個jinja2的異常

  開啓session功能,這裏必須要添加secret_key,如果在實例化的app中沒有 secret_key 會拋異常

1.4 特殊裝飾器

函數類:

@app.template_global()和@app.template_filter()

  和django中的inclusion_tag以及filter很類似   

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    {{ sums(15,15) }}
    {{ 22|a_b_c_sum(15,15) }}

</body>
</html>

在模板中執行函數,需要先定義一個函數:

app.py

from flask import Flask,render_template,Markup

app = Flask(__name__)


@app.template_global()
def sums(a,b):
    return a+b

@app.template_filter()
def a_b_c_sum(a, b, c):
    return a + b + c

@app.route("/")
def index():
    return render_template("login.html",tags="")   # 注意這裏也不一樣了

if __name__ == "__main__":
    app.run(port=5225,debug=True)

非函數類:

before_request 和 after_request

  @before_request註冊一個函數,在每次請求之前執行,返回None則運行通過

  @before_first_request,註冊一個函數,在處理第一個請求之前執行。它和@before_request一樣,唯一區別是它只執行一次

  @after_request 註冊一個函數,會在用戶請求得到response響應之後,還未返回用戶之前執行,它可以做統計訪問量來使用

  @teardown——request 註冊一個函數,即使有未處理的異常拋出,也在每次請求之後運行

from flask import Flask,request,redirect,session

app = Flask(__name__)
app.secret_key = "fsdfs"

@app.before_request
def is_login():  # 判斷是否登錄
    # 白名單設置,判斷爲登錄頁面時
    if request.path == "/login":
        # 跳過處理
        return None
    # 判斷session是不存在時
    if not session.get("user"):
        # 重定向到登錄頁面
        return redirect("/login")

@app.route("/login")
def login():
    pass

if __name__ == '__main__':
    app.run("0.0.0.0", 5000)

1.5 模板複用block

  和django中的模板使用方式一樣

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <h1>Welcome to My</h1>
    <h2>下面的內容是不一樣的</h2>
    {% block content %}

    {% endblock %}
</body>
</html>

login.html

{% extends "index.html" %}
{% block content %}
    <h4>歡迎登陸</h4>
    <form>
        用戶名:<input type="text" name="user">
        密碼:<input type="text" name="pwd">
        <input type="submit" value="提交">
    </form>
{% endblock %}

1.6 模板引用include

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <h1>Welcome to My</h1>

    {% include "login.html" %}
</body>
</html>

login.html

<form>
    用戶名:<input type="text" name="user">
    密碼:<input type="text" name="pwd">
    <input type="submit" value="提交">
</form>

1.7 模板中的過濾器

常用的過濾器

abs    # 絕對值
default  # 如果當前變量沒有值,則會使用參數中的值來替代
escape  # 轉義字符
first    #返回一個序列的第一個元素
format    #格式化字符串
last    # 返回一個序列的最後一個元素
length    # 返回一個序列的長度
join    # 拼接字符串
safe    # 關掉轉義
int    # 轉爲int類型
float    # 轉爲浮點類型
lower    # 轉換爲小寫
upper    # 轉換爲大寫
replace    # 替換
truncate  # 截取length長度的字符串
striptags  # 刪除字符串中所有的html標籤,如果出現多個空格,將替換成一個空格

default過濾器的使用

  他比較特別,使用必須要加上boolean=True

@app.route("/")
def index():
    content = {
       "direction":None
    }
    return render_template("index.html",**content)

index.html

<div>
    {{ direction|default("這是對default的使用說明",boolean=True) }}
</div>

效果

2. 路由相關(裝飾器中的參數)

2.1 實例

from flask import Flask,request

app = Flask(__name__)

@app.route("/info", methods=["GET", "POST"])
def student_info():
    stu_id = int(request.args["id"])    # 獲取前端url中的id值,注意格式類型
    return f"如家{stu_id}號房"  # Python3.6的新特性 f"{變量名}"

if __name__ == "__main__":
    app.run(port=5225,debug=True)

 效果:

2.3 endpoint 

  反向url地址,默認爲視圖函數名 (url_for)

from flask import Flask,request,url_for

app = Flask(__name__)

@app.route("/info", methods=["GET", "POST"],endpoint="r_info")
def student_info():
    print(url_for("r_info"))    # /info
    stu_id = int(request.args["id"])    # 獲取前端url中的id值,注意是格式類型
    return f"如家{stu_id}號房"  # Python3.6的新特性 f"{變量名}"

if __name__ == "__main__":
    app.run(port=5225,debug=True)

url欄輸入http://127.0.0.1:5225/info?id=2,會打印出如上代碼

2.3 url_for

  用於反向生成url,也可以附帶一些參數,比如想要完整的URL,可以設置_external爲Ture

from flask import Flask,request,url_for

app = Flask(__name__)

@app.route("/info", methods=["GET", "POST"],endpoint="r_info")
def student_info():
    print(url_for("r_info", _external=True))    # http://127.0.0.1:5225/info
    stu_id = int(request.args["id"])    # 獲取前端url中的id值,注意是格式類型
    return f"如家{stu_id}號房"  # Python3.6的新特性 f"{變量名}"

if __name__ == "__main__":
    app.run(port=5225,debug=True)

 # 這樣我們獲取了完整路徑,但是參數還未獲取,可以在後面再追加上我們的id, url_for("r_info", _external=True,id=stu_id),這樣就能獲取完整url

   對於url_for,我們還可以通過視圖函數解析出url

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

@app.route('/')
def hello_world():
    return url_for('my_list',page=6)   #url_for裏面:第一個是視圖函數,第二個是url需要的參數

@app.route('/list/<page>/')
def my_list(page):
    return 'my_list'

if __name__ == "__main__":
    app.run(port=5225,debug=True)

效果

  url_for裏面多餘的參數會當做搜索字符

@app.route('/')
def hello_world():
    return url_for('my_list',page=2,count=2,age=18)

@app.route('/list/<page>/')
def my_list(page):
    return 'my_list'

效果

2.4 defaults

  視圖函數的參數默認值{"nid":100}

 2.5 strict_slashes 

   url地址結尾符"/"的控制

   False : 無論結尾 "/" 是否存在均可以訪問

  True : 表示開啓路由嚴格匹配模式,結尾必須不能是 "/"

from flask import Flask

app = Flask(__name__)

@app.route("/info",strict_slashes=True)
def student_info():
    return "如家"

if __name__ == "__main__":
    app.run(port=5225,debug=True)

# 爲True,路由末尾不能再加反斜槓,不然報錯

# 爲False,路由末尾對反斜槓不做嚴格要求

2.6 redirect_to 

  url地址重定向

from flask import Flask
app = Flask(__name__)

@app.route("/info",redirect_to="/bbb")
def student_info():
    return "如家"

@app.route("/bbb")
def bbb():
    return "去你的"

# 輸入http://127.0.0.1:5225/info,它會自動發生跳轉,到http://127.0.0.1:5225/bbb

3. 動態參數路由

from flask import Flask,url_for
app = Flask(__name__)

@app.route("/info/<int:nid>",endpoint="r_info")
def student_info(nid):
    print(url_for("r_info", _external=True, nid=nid))
    return f"如家{nid}"

if __name__ == "__main__":
    app.run(port=5230,debug=True)

效果:

3.1常見 @app.route() 裝飾器中的動態參數

@app.route('/user/<username>')   # 不加參數的時候默認是字符串形式的
@app.route('/post/<int:post_id>')  # 指定int,說明是整型的
@app.route('/post/<float:post_id>')
@app.route('/post/<path:path>')
@app.route('/login', methods=['GET', 'POST'])

對應關係

DEFAULT_CONVERTERS = {
    'default':          UnicodeConverter,
    'string':           UnicodeConverter,
    'any':              AnyConverter,  接收多個路徑
    'path':             PathConverter,  和string類似,但是接收斜槓
    'int':              IntegerConverter,
    'float':            FloatConverter,
    'uuid':             UUIDConverter,
}

 對於any:

@app.route("/<any(blog,user):url_path>/<id>/")
def index(url_path,id):
    if url_path == 'blog':
        return '博客詳情%s' % id
    else:
        return '用戶詳情%s' % id

效果

對於path

@app.route('/article/<path:test>/')
def test_article(test):
    return 'test_article:{}'.format(test)

效果:

3.2 路由正則

具體代碼演示

from flask import Flask
from werkzeug.routing import BaseConverter


# 自定義正則轉換器
class RegexConverter(BaseConverter):
    def __init__(self, url_map, *args):
        super(RegexConverter, self).__init__(url_map)
        # 將接受的第1個參數當作匹配規則進行保存
        self.regex = args[0]


app = Flask(__name__)

# 將自定義轉換器添加到轉換器字典中,並指定轉換器使用時名字爲: re
app.url_map.converters['re'] = RegexConverter


@app.route('/user/<re("[0-9]{3}"):user_id>')
def user_info(user_id):
    return "user_id 爲 %s" % user_id


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

效果

也可以參考祥哥博客

4.實例化Flask參數

4.1 flask配置

開啓debug模式

from flask import Flask

app = Flask(__name__)  # type:Flask
app.config["DEBUG"] = True

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

config中的所有key值

{
    'DEBUG': False,  # 是否開啓Debug模式
    'TESTING': False,  # 是否開啓測試模式
    'PROPAGATE_EXCEPTIONS': None,  # 異常傳播(是否在控制檯打印LOG) 當Debug或者testing開啓後,自動爲True
    'PRESERVE_CONTEXT_ON_EXCEPTION': None,  # 一兩句話說不清楚,一般不用它
    'SECRET_KEY': None,  # 之前遇到過,在啓用Session的時候,一定要有它
    'PERMANENT_SESSION_LIFETIME': 31,  # days , Session的生命週期(天)默認31天
    'USE_X_SENDFILE': False,  # 是否棄用 x_sendfile
    'LOGGER_NAME': None,  # 日誌記錄器的名稱
    'LOGGER_HANDLER_POLICY': 'always',
    'SERVER_NAME': None,  # 服務訪問域名
    'APPLICATION_ROOT': None,  # 項目的完整路徑
    'SESSION_COOKIE_NAME': 'session',  # 在cookies中存放session加密字符串的名字
    'SESSION_COOKIE_DOMAIN': None,  # 在哪個域名下會產生session記錄在cookies中
    'SESSION_COOKIE_PATH': None,  # cookies的路徑
    'SESSION_COOKIE_HTTPONLY': True,  # 控制 cookie 是否應被設置 httponly 的標誌,
    'SESSION_COOKIE_SECURE': False,  # 控制 cookie 是否應被設置安全標誌
    'SESSION_REFRESH_EACH_REQUEST': True,  # 這個標誌控制永久會話如何刷新
    'MAX_CONTENT_LENGTH': None,  # 如果設置爲字節數, Flask 會拒絕內容長度大於此值的請求進入,並返回一個 413 狀態碼
    'SEND_FILE_MAX_AGE_DEFAULT': 12,  # hours 默認緩存控制的最大期限
    'TRAP_BAD_REQUEST_ERRORS': False,
    # 如果這個值被設置爲 True ,Flask不會執行 HTTP 異常的錯誤處理,而是像對待其它異常一樣,
    # 通過異常棧讓它冒泡地拋出。這對於需要找出 HTTP 異常源頭的可怕調試情形是有用的。
    'TRAP_HTTP_EXCEPTIONS': False,
    # Werkzeug 處理請求中的特定數據的內部數據結構會拋出同樣也是“錯誤的請求”異常的特殊的 key errors 。
    # 同樣地,爲了保持一致,許多操作可以顯式地拋出 BadRequest 異常。
    # 因爲在調試中,你希望準確地找出異常的原因,這個設置用於在這些情形下調試。
    # 如果這個值被設置爲 True ,你只會得到常規的回溯。
    'EXPLAIN_TEMPLATE_LOADING': False,
    'PREFERRED_URL_SCHEME': 'http',  # 生成URL的時候如果沒有可用的 URL 模式話將使用這個值
    'JSON_AS_ASCII': True,
    # 默認情況下 Flask 使用 ascii 編碼來序列化對象。如果這個值被設置爲 False ,
    # Flask不會將其編碼爲 ASCII,並且按原樣輸出,返回它的 unicode 字符串。
    # 比如 jsonfiy 會自動地採用 utf-8 來編碼它然後才進行傳輸。
    'JSON_SORT_KEYS': True,
    #默認情況下 Flask 按照 JSON 對象的鍵的順序來序來序列化它。
    # 這樣做是爲了確保鍵的順序不會受到字典的哈希種子的影響,從而返回的值每次都是一致的,不會造成無用的額外 HTTP 緩存。
    # 你可以通過修改這個配置的值來覆蓋默認的操作。但這是不被推薦的做法因爲這個默認的行爲可能會給你在性能的代價上帶來改善。
    'JSONIFY_PRETTYPRINT_REGULAR': True,
    'JSONIFY_MIMETYPE': 'application/json',
    'TEMPLATES_AUTO_RELOAD': None,
}

4.2 對於配置的修改

  我們可以創建一個setting文件

class FlaskSetting(object):
    DEBUG = True

  需要使用,直接導入就可以

 4.3 實例化配置

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  # 主模塊所在的目錄的絕對路徑,默認項目目錄

4.4 template_folder

  如果設置template_folder = 'templates',這裏面的templates它是相對路徑!

   我們在使用該模板時,應該這麼設置  template_folder = '../templates'

結構圖:

./
├── bin
│   └── app.py
├── static
│   └── learning.jpg
└── templates
    └── login.html

案例:

from flask import Flask,render_template
from flask_login import login_required  # 第三方包,需要下載
app = Flask(__name__,template_folder="../templates")    # 有時候會找不到,需加上template_folder


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


@app.route("/log")
@login_required        # 不能直接訪問該路由
def index():
    return render_template("index.html")


if __name__ == "__main__":
    app.run(port=5230,debug=True)

 4.5 static_folder

  靜態文件目錄的路徑 默認當前項目中的static目錄

結構圖

./
├── bin
│   └── app.py
├── static
│   └── learning.jpg
└── templates
    └── login.html

app.py

from flask import Flask,render_template

app = Flask(__name__,template_folder="../templates",static_folder="../static")

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

if __name__ == "__main__":
    app.run(port=5230,debug=True)

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>頭像</h3>
<img src="/static/learning.jpg" alt="">
</body>
</html>

 效果

4.6 static_url_path

from flask import Flask,render_template

app = Flask(__name__,template_folder="../templates",static_folder="../static",static_url_path="/app")

@app.route("/")
def index():
    print(app.static_folder)    # C:\Users\Learning\Desktop\ffflask\bin\../static
    print(app.static_url_path)  # /app
    return render_template("login.html")

if __name__ == "__main__":
    app.run(port=5230,debug=True)

 5. 內置session

  上面案例已經使用過session,這裏只強調一點,使用session必須配製secret_key,它是一段祕鑰字符串,自己隨意填寫

from flask import session
app = Flask(__name__)
app.secret_key = "ask"

一般session我們可以做登錄驗證使用

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章