Web後端學習筆記 Flask(4)視圖函數

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

---------------------------------------------------------------------------------------------------------------------------------------

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