Flask中的視圖函數以及視圖類:
添加視圖函數還可以通過下面的方式add_url_rule進行:
app.add_url_rule(rule, endpoint, view_func):
rule: 對應的url
endpoint:相當於給url取一個名字
view_func:視圖函數
-------------------------------------------------------------------------------------------------------------------------------
endpoint用於反轉視圖函數得到url,如果給endpoint賦了值,那麼在使用url_for()獲取視圖函數的url時,就不能再使用函數名作爲參數,而是應該使用endpoint來獲取視圖函數的url
from flask import Flask, url_for
app = Flask(__name__)
app.config["TEMPLATE_AUTO_RELOAD"] = True
@app.route('/')
def hello_world():
print(url_for("theList")) # 這裏url_for的參數值只能是theList, 不能是my_list
return 'Hello World!'
def my_list():
return "This is item list"
app.add_url_rule(rule="/list/", endpoint="theList", view_func=my_list)
if __name__ == '__main__':
app.run(debug=True)
標準類視圖及其使用場景:
如何將類變成一個視圖函數:類視圖支持繼承,寫完類視圖,需要通過add_url_rule進行添加
1. 標準類視圖:
標準類視圖繼承自flask.views.View,並且在子類中必須實現dispatch_request方法,這個方法類似於視圖函數,也要返回一個基於Response或者其子類的對象.
from flask import Flask, url_for, views
app = Flask(__name__)
app.config["TEMPLATE_AUTO_RELOAD"] = True
@app.route('/')
def hello_world():
return 'Hello World!'
class ListView(views.View):
def dispatch_request(self):
"""
類視圖中必須實現這一個方法
:return:
"""
return "This is list view"
app.add_url_rule(rule="/list/", endpoint="list", view_func=ListView.as_view("list"))
# 這裏的as_view會將一個對象轉化爲函數,賦值給視圖函數, 參數name是給轉換後的函數取的名字
if __name__ == '__main__':
app.run(debug=True)
如果制定了endpoint,那麼在使用url_for時必須使用endpoint, 如果沒有指定,那麼就可以使用as_view中的名字。
類試圖的應用:
a. 例如有url需要返回字典
from flask import Flask, views, jsonify
app = Flask(__name__)
app.config["TEMPLATE_AUTO_RELOAD"] = True
@app.route('/')
def hello_world():
return 'Hello World!'
class JsonView(views.View): # 定義基類
def get_data(self):
return NotImplementedError
def dispatch_request(self):
return jsonify(self.get_data())
class ListView(JsonView):
def get_data(self):
return {"username": "Tom", "password": "2345"}
app.add_url_rule(rule="/list/", endpoint="list", view_func=ListView.as_view("list"))
# 這裏的as_view會將一個對象轉化爲函數,賦值給視圖函數, 參數name是給轉換後的函數取的名字
if __name__ == '__main__':
app.run(debug=True)
JsonView類是基類,定義get_data()方法,ListView類是JsonView類的基類,在基類中,重新實現了get_data()方法,在調用ListView中的dispatch_request()方法的時候,由於ListView中未重寫dispatch_request()方法,所以回去調用父類中的dispatch_request()方法,在父類的dispatch_request()方法中會調用get_data()方法,而在子類ListView中實現了get_data方法,所以實際調用的是子類ListView中的方法,返回字典
b. 有幾個url需要返回相同的變量:
例如,在登陸頁面以及註冊頁面,需要展示相同的廣告,則可以通過下面繼承的方法實現:
from flask import Flask, views, render_template
app = Flask(__name__)
app.config["TEMPLATE_AUTO_RELOAD"] = True
@app.route('/')
def hello_world():
return 'Hello World!'
class AdsView(views.View): # 廣告內容
def __init__(self):
super(AdsView, self).__init__() # 調用父類的init方法
self.ad_content = {
"product": "GMCC-1001"
}
def dispatch_request(self):
return NotImplementedError # 因爲基類中的這個方法不會被調用
class LoginView(AdsView):
def dispatch_request(self):
return render_template("html/login.html", **self.ad_content)
class RegisterView(AdsView):
def dispatch_request(self):
return render_template("html/registry.html", **self.ad_content)
app.add_url_rule(rule="/login/", endpoint="login", view_func=LoginView.as_view("login"))
app.add_url_rule(rule="/registry/", endpoint="registry", view_func=RegisterView.as_view("registry"))
if __name__ == '__main__':
app.run(debug=True)
通過這種方法,可已將相同的廣告內容展示在不同的頁面。且修改起來更加的容易。
2. 基於請求方法的視圖
Flask還提供了另一種類視圖,flask.view.Methodview,對每個http執行不同的函數(映射到對應方法的小寫的同名方法上),這對restful API尤其有用。
基於方法的類視圖,是根據請求的“method”不同來執行不同的方法的,如果用戶是發送的“get”請求,那麼將會執行這個類的get方法,如果發送的是post請求,將會執行類的post方法。其他的“method”也類似,例如delete,put方法
from flask import Flask, views, render_template, request
app = Flask(__name__)
app.config["TEMPLATE_AUTO_RELOAD"] = True
@app.route('/')
def hello_world():
return 'Hello World!'
class LoginView(views.MethodView):
def get(self, error=None):
return render_template("html/login.html", error=error)
def post(self):
"""
獲取post請求提交的參數
:return:
"""
username = request.form.get("username")
password = request.form.get("password")
if username == "knight" and password == "123456":
return self.get(error="success")
else:
return self.get(error="fail")
app.add_url_rule(rule="/login/", view_func=LoginView.as_view("login"))
if __name__ == '__main__':
app.run(debug=True)
前端代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陸</title>
</head>
<body>
<form action="" method="post">
<table>
<tr>
<td>用戶名</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密碼</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="點擊登陸"></td>
</tr>
</table>
{% if error %}
{% if error == "success" %}
<p style="color: green">登陸成功</p>
{% else %}
<p style="color: red">登陸失敗</p>
{% endif %}
{% endif %}
</form>
</body>
</html>
類視圖中使用裝飾器:
1. 如果使用的是函數視圖,那麼自己定義的裝飾器必須放在“app.route()”裝飾器的下面才能生效。否則這個裝飾器不能起作用。
2. 類視圖的裝飾器需要重寫類視圖的一個屬性decorates,這個類屬性是一個列表或者元組,裏面裝的就是所有的裝飾器。
應用場景:例如網站上的個人信息頁面和設置頁面,在跳轉到這些頁面的時候,如果用戶沒有登陸,則會自動跳轉到登陸頁面,
提醒用戶登陸。只有在登錄狀態下才能訪問這些頁面,下面通過裝飾器模擬這一功能。
from flask import Flask, views, render_template, request
from functools import wraps
app = Flask(__name__)
app.config["TEMPLATE_AUTO_RELOAD"] = True
def login_required(func): # 定義裝飾器
@wraps(func) # 保留參數 函數func的一些屬性,如__name__屬性等
def wrapper(*args, **kwargs):
username = request.args.get("username")
if username and username == "Tom":
return func(*args, **kwargs)
else:
return "請先登陸"
return wrapper
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/setting/')
@login_required # 自定義的裝飾器應該放在url的下main
def setting():
return "User setting"
# 給類視圖添加裝飾器
class ProfileView(views.View):
decorators = [login_required]
def dispatch_request(self):
return "這是個人頁面"
app.add_url_rule("/profile/", view_func=ProfileView.as_view("profile"))
if __name__ == '__main__':
app.run(debug=True)
在這些頁面中,只有請求參數中有用戶名參數的時候,才能夠跳轉到相應的頁面,否則會提示登陸。
藍圖的基本使用:
藍圖用於將一個大型Flask項目分層解耦,進行模塊化劃分,可以將相同模塊的視圖函數放在同一個文件中,統一進行管理
例如,網站主要可以劃分爲新聞,電影,圖書,個人中心四個模塊,則可以按照如下的方式進行劃分:
user.py文件:(初始化藍圖)
# -*- coding: utf-8 -*-
from flask import Blueprint
user_bp = Blueprint("user", __name__, url_prefix="/user") # 初始化藍圖
# 個人中心
@user_bp.route('/profile/')
def profile():
return "個人中心頁面"
@user_bp.route("/settings/")
def settings():
return "設置頁面"
news.py文件 (初始化藍圖), 同時在news.py中渲染html文件的方法不變:
# -*- coding: utf-8 -*-
from flask import Blueprint, render_template
news_bp = Blueprint("news", __name__, url_prefix="/news")
@news_bp.route("/news_list/")
def news_list():
return render_template("html/news_list.html")
@news_bp.route("/news_detail/")
def news_detail():
return "新聞詳情"
在app.py文件中,註冊上面創建的藍圖
from flask import Flask, views, render_template, request
from blueprints.user import user_bp
from blueprints.news import news_bp
app = Flask(__name__)
app.register_blueprint(user_bp)
app.register_blueprint(news_bp)
app.config["TEMPLATE_AUTO_RELOAD"] = True
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
這樣就將項目中的視圖函數分模塊進行管理。
url_prefix:url前綴,如果加了,則視圖函數對應的url前面必須有前綴,且只能有一個斜槓
route中還可以指定template_folder參數,如果制定了這個參數template_folder=“xxx”,那麼flask在渲染模板的時候,首先會去項目中的templates文件夾中尋找,如果沒有找到,flask接下來會去blueprints/xxx文件夾中尋找模板文件。
藍圖中靜態文件的尋找規則:
1. 在模板文件中,加載靜態文件,如果使用url_for('static'),那麼就會在app指定的靜態文件夾目錄下查找靜態文件
2.如果在加載靜態文件的時候,指定了藍圖的名字,比如“news.static”,那麼Flask就會到這個藍圖指定的static_folder下查找靜態文件。
url_for反轉藍圖注意事項:
如果需要跨文件反轉視圖函數,則需要指定視圖函數的藍圖名字,再加上視圖函數名字,例如:
@app.route('/')
def hello_world():
print(url_for("news.news_list"))
return 'Hello World!'
例如,需要反轉news_list視圖函數,則需要在加上其藍圖的名字纔可以,在模板中和在python文件中的用法一樣,同樣需要加藍圖的名字。
即使在同一個藍圖中反轉視圖函數,也需要指定藍圖的名字。
子域名實現詳解:
1. 使用藍圖技術
2. 在創建藍圖對象的時候,需要傳遞一個"subdomain"參數,來指定這個子域名的前綴:
3. 需要在主app文件中,需要配置serve name參數:
【注】IP地址不能有子域名,localhost不能有子域名
例如,CMS子域名:
# -*- coding: utf-8 -*-
from flask import Blueprint
cms_bp = Blueprint("cms", __name__, subdomain="cms")
@cms_bp.route("/")
def index():
return "Cms index Page"
在app.py文件中設置:
from blueprints.cms import cms_bp
app.register_blueprint(cms_bp)
app.config["TEMPLATE_AUTO_RELOAD"] = True
app.config["SERVER NAME"] = "jd.com:5000"
# 修改host文件:
# 127.0.0.1 jd.com
# 127.0.0.1 cms.jd.com
此時設置完畢計算機的host文件後,在本地計算機訪問jd.com,就會映射到127.0.0.1
---------------------------------------------------------------------------------------------------------------------------------------