Python学习笔记--Flask视图高级

知识点

  1. 使用add_url_rule添加路由规则
  2. 标准类视图的介绍
  3. 基于调度方法的类视图介绍
  4. 在类中使用装饰器
  5. 蓝图的基本使用
  6. url的前缀
  7. 在蓝图中寻找模板和静态资源文件
  8. 子域名的使用方法

add_url_rule()的使用

在Flask中,如果视图只是用函数来构建的话,可以在函数上面加个装饰器@app.route()来注册路由,但如果用到类的话,这个装饰器就不能放到类里面使用了,因此类可以用add_url_rule()方法来注册路由。当然这个add_url_rule()方法并不只局限类的使用,函数也能使用。

比如下面的代码,我希望在打开首页的时候在控制台上打印个人中心(profile)的路由

from flask import Flask
from flask import url_for

app = Flask(__name__)
app.config["TEMPLATES_AUTO_RELOAD"] = True


@app.route("/")
def index():
    # 由于add_url_rule已经给了endpoint,因此这里的url_for只能填geren
    print(url_for("geren"))
    return "首页"


def profile():
    return "个人中心"


# add_url_rule添加路由规则.
# endpoint相当于给路由取了个名字,因此只能通过endpoint的值找到这个路由,
# 如果没给的话,那就是通过view_func的值来找到路由
# view_func指定一个路由函数,函数后面不能带括号.
app.add_url_rule("/profile/", endpoint="geren", view_func=profile)


if __name__ == '__main__':
    app.run(debug=True)
  • 在这里我先是通过add_url_rule注册路由,并且给它传入了3个参数
    • 第一个参数是路由地址
    • 第二个参数endpoint相当于给这个路由取了个名字
    • 第三个参数view_func是路由的函数。注意,这个位置函数名称后面不能加括号
  • 然后在index函数中添加打印函数,将url打印出来。但是在add_url_rule已经给了endpoint参数,因此这里的url_for的参数只能填endpoint的值,否则会找不到。

类视图

标准类视图

标准类视图需要导入views模块

from falsk import views

然后创建类并继承views.View
要注意的是,继承了views.View那必须要重写dispatch_request方法,这是在代码里规定的,否则会抛出异常

class ListView(views.View):
    def dispatch_request(self):
        """
        代码规定了只要继承views.View,都必须要重写这个方法,否则会抛出异常
        """
        return "类视图"

源码:
在这里插入图片描述
然后就可以用add_url_rule()注册路由

from flask import Flask
from flask import url_for
from flask import views

app = Flask(__name__)
app.config["TEMPLATES_AUTO_RELOAD"] = True


class ListView(views.View):
    def dispatch_request(self):
        """
        代码规定了只要继承views.View,都必须要重写这个方法,否则会抛出异常
        """
        return "类视图"


# 类视图可以不用endpoint,有as_view就可以了,因为也是给路由取名。但如果给了endpoint,那就只能用endpoint.
app.add_url_rule("/list/", endpoint="list", view_func=ListView.as_view("list"))


if __name__ == '__main__':
    app.run(debug=True)
  • 这里的add_url_rule注册路由要注意view_func给值不能直接把类名给过去就算了,还需要在后面加上一个方法as_view,这个方法需要传一个name参数,其实也相当于给路由取了个名字。
  • 因此endpoint和as_view的功能有点重叠了,所以endpoint其实可以不传的。
  • 如果传了endpoint也同时有as_view,那路由的名字用的是endpoint的。

标准类视图的案例

给页面返回JSON数据并显示

# 模拟百度翻译返回JSON数据
from flask import Flask
from flask import views
from flask import jsonify


class JsonView(views.View):
    def get_response(self):
        raise NotImplementedError

    def dispatch_request(self):
        response = self.get_response()
        return jsonify(response)


class JsonListView(JsonView):
    def get_response(self):
        return {"username": "hello world"}


app.add_url_rule("/listjson/", view_func=JsonListView.as_view("listjson")) # 注册路由


if __name__ == '__main__':
    app.run(debug=True)
  • 首先创建了JsonView类并创建了两个方法
    • 首先get_response方法在子类中是必须要重写的,不然就会抛出异常
    • 然后是dispatch_request方法,它调用get_response并且将获取到的JSON数据返回
  • 接着创建了JsonListView类并继承JsonView类,然后重写get_response方法,给了它一个返回值。

这样页面就可以得到一个JSON数据
在这里插入图片描述

基于调度方法的视图

基于调度方法的视图需要导入view

from falsk import views

创建类视图比继承view.MethodView
与标准类视图不同的是,继承view.MethodView的子类不需要重写dispatch_request方法

class LoginView(views.MethodView):
	pass

实例:

class LoginView(views.MethodView):
    def get(self):
        return render_template("views/login.html")

    def post(self):
        name = request.form.get("name")
        password = request.form.get("password")

        if name == "AAA" and password == "123":
            return "登录成功"
        else:
            return render_template("views/login.html", error="账号密码错误")

在类中使用装饰器

这里做个案例,在中使用装饰器,实现进入个人中心前需要先登录

  1. 首先定义装饰器
def login_required(fun):
    def wrapper(*args, **kwargs):
        username = request.form.get("username")
        if username:
            return fun(*args, **kwargs)
        else:
            return "请先登录"
    return wrapper
  1. 将在类中使用decorators属性绑定装饰器,decorators是已经定义好的属性,必须要用它
class ProFileView(views.View):
    #在类中用装饰器
    decorators = [login_required]

    def dispatch_request(self):
        return "个人页面"

蓝图和子域名

之前我们写的url和视图函数都是处在同一个文件,如果项目比较大的话,这显然不是一个合理的结构,而蓝图可以优雅的帮我们实现这种需求。

蓝图的基本使用

  1. 首先创建主入口文件app.py
from flask import Flask
from blueprints.news import news_bp
from blueprints.book import book_bp

app = Flask(__name__)
app.register_blueprint(news_bp)  # 将蓝图注册进url映射中
app.register_blueprint(book_bp)  # 将蓝图注册进url映射中
app.config["TEMPLATES_AUTO_RELOAD"] = True


@app.route("/")
def index():
    return "这是首页"


if __name__ == '__main__':
    app.run(debug=True)
  • 主入口这里需要注册将蓝图注册到url映射中,否则在浏览器上是访问不到蓝图的路由,用app.register_blueprint注册。蓝图的创建在下面。
  1. 创建blueprints文件夹(蓝图目录),然后再里面创建news.py, book.py
  2. news.py写入代码
from flask import Blueprint

news_bp = Blueprint("news", __name__)


@news_bp.route("/news/")
def news():
    return "新闻页面"
  1. book.py写入代码
from flask import Blueprint

book_bp = Blueprint("book", __name__)


@book_bp.route("/book/")
def news():
    return "图书页面"
  • news和book文件中,都需要实例化Blueprint,第一个参数是名字,第二个参数是当前文件名

URL前缀

URL前缀用到的参数是url_prefix

from flask import Blueprint

# 加了url_prefix, 路由时从book开始
book_bp = Blueprint("book", __name__, url_prefix="/book")

# 给了url_prefix,因此这里写个/就可以了
@book_bp.route("/")
def news():
    return "图书页面"

寻找模板和静态资源文件

寻找模板

在templates目录下创建news.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>这是templates中的新闻首页</h1>
</body>
</html>

修改news.py的代码,返回news.html模板

from flask import Blueprint, render_template

news_bp = Blueprint("news", __name__, url_prefix="/news")


@news_bp.route("/")
def news():
    # return "新闻页面"
    return render_template("news.html")

默认情况下,蓝图也是在templates目录下寻找模板。
但是,Blueprint有个template_folder参数,他可以指定一个模板目录。
在blueprints目录下创建coder文件夹,然后在里面创建news.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>这是蓝图里的HTML</h1>
</body>
</html>

然后修改news.py代码,添加template_folder参数

from flask import Blueprint, render_template

news_bp = Blueprint("news", __name__, url_prefix="/news", template_folder="coder")


@news_bp.route("/")
def news():
    # return "新闻页面"
    return render_template("news.html")

此时的目录结构如下:
在这里插入图片描述
可以发现,目前templates目录和coder目录下都有news.html文件,但是运行代码后可以发现,实际上还是找到了templates目录下的news.html文件。
默认情况下是优先在templates目录下找;如果没有就去template_folder参数给的路径找,也就是coder目录下找;如果还是没有,那就会报错。 不过大部分情况下还是放在templates目录下就可以了。

  • 另外template_folder参数给的路径是相对路径,相对于当前文件目录下的。也可以直接给绝对路径。

寻找静态资源文件

一般情况下静态资源文件也还是放在static目录下,蓝图还是提供了一个static_folder参数

  • static_folder参数会指定静态资源目录,模板会直接到这个目录下去找静态文件。
    如下,在blueprints目录下创建了blue目录并在里面创建了news.css文件,写入背景颜色:
body{
    background: blue;
}

然后修改news.py文件

from flask import Blueprint, render_template

news_bp = Blueprint("news", __name__, url_prefix="/news", template_folder="coder", static_folder="blue")


@news_bp.route("/")
def news():
    # return "新闻页面"
    return render_template("news.html")

然后再修改模板

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{{ url_for("news.static", filename="news.css") }}">
</head>
<body>
    <h1>这是templates中的新闻首页</h1>
</body>
</html>
  • 模板这里的url_for第一个参数要使用XXXX.static
  • 这样模板就会在blue目录下找到news.css文件
  • 这里与模板有个区别,就是static就算也有相同的css文件,但它还是会从static_folder指定的目录下找css文件。

url_for

有蓝图的情况下,想在主入口app.py文件要打印蓝图的路由,url_for的第一个参数要填 “蓝图的名字.方法名字”
蓝图里也是同理,一样是url_for的第一个参数要填 “蓝图的名字.方法名字”

from flask import Flask, url_for
from blueprints.news import news_bp
from blueprints.book import book_bp

app = Flask(__name__)
app.register_blueprint(news_bp)  # 将蓝图注册进url映射中
app.register_blueprint(book_bp)  # 将蓝图注册进url映射中
app.config["TEMPLATES_AUTO_RELOAD"] = True


@app.route("/")
def index():
    # url_for的第一个参数要填 "蓝图的名字.函数名字"
    print(url_for("news.news"))
    return "这是首页"


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

子域名

子域名在许多网站中都用到了,比如一个网站叫做xxx.com,那么我们可以定义一个子域名cms.xxx.com来作为cms管理系统的网址,子域名的实现一般也是通过蓝图来实现。比如很多网站都会有前台和后台,那么后台的域名就有可能是个子域名。
子域名需要用到subdomain参数,在blueprints目录下创建cms.py文件并写入代码

from flask import Blueprint

cms_bp = Blueprint("cms", __name__, subdomain="cms")


@cms_bp.route("/")
def cms():
    return "CMS页面"

运行代码,不过在浏览器上不能像平常那样输入http://127.0.0.1:5000/cms/,要改为http://cms.127.0.0.1:5000/。不过一般情况下这样还是不能够进入页面,还需要做些配置。
window系统进入C:\Windows\System32\drivers\etc/,编辑host文件,默认情况下host文件是空的,或者有一堆注释,如果里面有值可能是通过某些程序或者人为修改过。
在最底下添加

127.0.0.1  flask.com
127.0.0.1  cms.flask.com

然后再次修改主入口app.py文件,配置SERVER_NAME

from flask import Flask, url_for
from blueprints.news import news_bp
from blueprints.book import book_bp
from blueprints.cms import cms_bp

app = Flask(__name__)
app.register_blueprint(news_bp)  # 将蓝图注册进url映射中
app.register_blueprint(book_bp)  # 将蓝图注册进url映射中
app.register_blueprint(cms_bp)  # 将蓝图注册进url映射中
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.config["SERVER_NAME"] = "flask.com:5000"  # 配置SERVER_NAME


@app.route("/")
def index():
    # url_for的第一个参数要填 "蓝图的名字.函数名字"
    print(url_for("news.news"))
    return "这是首页"


if __name__ == '__main__':
    app.run(debug=True)
  • 这时在网页上输入http://cms.flask.com:5000/才能访问cms页面,并且就算访问主页也只能输入http://flask.com:5000/访问
  • 要注意SERVER_NAME不支持IP的形式
  • 然后这样的配置其实只是在局域网内有效,正式环境不可能这样配置。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值