目录
知识点
- 使用add_url_rule添加路由规则
- 标准类视图的介绍
- 基于调度方法的类视图介绍
- 在类中使用装饰器
- 蓝图的基本使用
- url的前缀
- 在蓝图中寻找模板和静态资源文件
- 子域名的使用方法
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="账号密码错误")
在类中使用装饰器
这里做个案例,在中使用装饰器,实现进入个人中心前需要先登录
- 首先定义装饰器
def login_required(fun):
def wrapper(*args, **kwargs):
username = request.form.get("username")
if username:
return fun(*args, **kwargs)
else:
return "请先登录"
return wrapper
- 将在类中使用decorators属性绑定装饰器,decorators是已经定义好的属性,必须要用它
class ProFileView(views.View):
#在类中用装饰器
decorators = [login_required]
def dispatch_request(self):
return "个人页面"
蓝图和子域名
之前我们写的url和视图函数都是处在同一个文件,如果项目比较大的话,这显然不是一个合理的结构,而蓝图可以优雅的帮我们实现这种需求。
蓝图的基本使用
- 首先创建主入口文件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注册。蓝图的创建在下面。
- 创建blueprints文件夹(蓝图目录),然后再里面创建news.py, book.py
- news.py写入代码
from flask import Blueprint
news_bp = Blueprint("news", __name__)
@news_bp.route("/news/")
def news():
return "新闻页面"
- 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的形式
- 然后这样的配置其实只是在局域网内有效,正式环境不可能这样配置。