路由、视图、模板配合才能完成较完整的请求响应过程。
前面简单了解了以上三者,这里将进一步介绍路由机制与视图。
一,函数视图
就像在创建flask项目:Hello,Flask!与flask:flask模板——使用Jinja2中用过的那样,视图用于进行业务逻辑处理。
发现没有,这里的视图处理都是在一个函数中进行的,所以这个函数叫视图函数。视图函数完全由开发人员根据需求自定义开发,具有很高的灵活度。
然而这只是实现视图功能的一种方式,另一种在后面介绍。
二,路由注册与路由传参
1,路由注册
URL需要使用路由装饰器进行注册:
@app.route('/') # 注册路由
def hello_world():
return 'Hello World!'
- 可以将多个URL注册到同一个函数视图。
除了使用装饰器注册路由,还可以使用 Flask 实例的 add_url_rule()
方法手动关联 URL 与视图:
# app.py:
from flask import Flask, escape, url_for, redirect, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
def url_test():
return '<h2>通过add_url_rule()过来</h2>'
app.add_url_rule('/test/', endpoint='url_test', view_func=url_test)
# 使用 endpoint 端点参数为URL的命名。Flask 本身假定视图函数的名称为端点
- 通过
@app.route
源码self.add_url_rule(rule, endpoint, f, **options)
可以看出,它还是通过add_url_rule()
实现路由注册的。
2,URL传参
可以直接在URL最后添加 /<parameter_name>
:
@app.route('/user/<name>')
def list_name(name): # URL中的参数会作为关键字参数传递给函数视图
return "接收到的名字为: %s" % name
3,为参数制定规则
通常会添加一个转换器来为路由参数指定类型规则,有如下转换器类型可用:
- 不指定这个规则时,默认使用
string
类型。
例如,指定 int 类型的参数:
@app.route('/news/<int:id>')
def list_news(id):
return "接收到的id为: %s" % id
4,为路由指定请求方式
需要使用 methods
参数来处理不同的 HTTP 方法,默认的是GET。
from flask import request
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return do_the_login()
else:
return show_the_login_form()
三,URL反转与页面重定向
到此为止,我们的URL都是在路由装饰器里面写死的,显然这不利于灵活使用URL,这就需要使用URL反转,它可以:
- 集中管理URL
- 避免相对路径的使用错误
- 给指定的函数构造 URL
1,在视图中构建反转URL
使用 url_for(endpoint, **values)
可在视图中获取反转的 URL:
- 第一个参数是函数视图名。
- 后面的参数将作为路由参数。
# app.py:
from flask import Flask, escape, url_for
app = Flask(__name__)
@app.route('/')
def index():
return url_for('blog', blog='xxxxxxxxxxx')
@app.route('/user/blog/<blog>')
def blog(blog):
return '<h3>blog: {}</h3>'.format(blog)
@app.route('/login')
def login():
return 'login'
@app.route('/user/<username>')
def profile(username):
return '{}\'s profile'.format(escape(username))
with app.test_request_context():
print(url_for('index'))
print(url_for('login'))
print(url_for('login', next='/'))
print(url_for('profile', username='John Doe'))
2,在模板中构建URL
使用 {{ url_for('function_name')}}
:
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block body %}
<h4>welcome!</h4>
<p><a href="{{ url_for('profile', username='John Doe') }}">user's profile</a></p>
{% endblock %}
3,页面重定向
页面重定向允许在某操作执行前或执行后跳转到别的页面执行别的操作,比如想要编辑博客内容,就应先跳转到登陆界面进行登录。
flask 使用 redirect()
函数实现重定向。
# app.py:
from flask import Flask, escape, url_for, redirect, render_template
app = Flask(__name__)
@app.route('/')
def index():
url = url_for('show_index')
return redirect(url)
@app.route('/index')
def show_index():
return render_template('index.html')
@app.route('/user/<username>')
def profile(username):
return '{}\'s profile'.format(escape(username))
- 访问http://127.0.0.1:5000/会跳转至http://127.0.0.1:5000/index
四,类视图
当然,在不同项目中开发功能重复的视图处理函数是相当枯燥的,虽然 ctrl+c 与 ctrl+v 解决了很多问题,但使用 flask 的类视图进行业务逻辑处理更有意思。
类视图是一类可插拔的视图,即用即插,它们已经实现了一些通用功能,具有很大的灵活性。
1,标准类视图
一个例子:
from flask import Flask, render_template, views
app = Flask(__name__)
class Ads(views.View):
def __init__(self):
super().__init__()
self.context = {
'ads': '这是广告!'
}
class Index(Ads):
def dispatch_request(self):
self.context['title'] = '首页'
print(self.context)
return render_template('index.html', **self.context)
class Login(Ads):
def dispatch_request(self):
self.context['title'] = '登录'
return render_template('login.html', **self.context)
class Register(Ads):
def dispatch_request(self):
self.context['title'] = '注册'
return render_template('register.html', **self.context)
app.add_url_rule(rule='/', endpoint='index', view_func=Index.as_view('Index'))
app.add_url_rule(rule='/login/', endpoint='login', view_func=Login.as_view('login'))
app.add_url_rule(rule='/register/', endpoint='register', view_func=Register.as_view('register'))
if __name__ == '__main__':
app.run(debug=True)
- Ads就是一个类视图,它必须继承自
flask.views.View
,其中self.context
设置了模板上下文,其内容可直接在模板中使用。 - Index、Login、Register继承自Ads,它们必须实现
dispatch_request
方法,使用时必须在add_url_rule
方法实现路由与视图的关联,其中rule
定义URL规则,由view_func=class_view.as_view('urlname')
完成关联。
index.html:
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block body %}
<h1>{{ ads }}</h1>
{% endblock %}
login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h1>这是登录页面!</h1>
<p><a href="{{ url_for('register') }}">请先注册</a></p>
{{ ads }}
</body>
</html>
register.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
这是注册页面!!
{{ ads }}
</body>
</html>
2,在类视图中处理不同 HTTP 请求
首先,我们可以在类视图中添加值为列表的 methods
属性来限定视图能处理的请求方法:
class MyView(View):
methods = ["GET", "POST"]
def dispatch_request(self):
if request.method == "POST":
...
...
app.add_url_rule('/my-view', view_func=MyView.as_view('my-view'))
可见,需要进一步通过判断语句区分处理不同的请求方法。
为了简化判断,flask 提供了另一种类视图——基于方法的类视图,它可根据不同的 HTTP 请求类型执行不同的操作,我们要做的就是在实现类视图的时候将显式地将不同的处理分配给不同的请求方法:
class UserAPI(MethodView):
def get(self):
users=User.query.all()
...
def post(self):
user=User.from_form_data(request.form)
...
app.add_url_rule('/users/',view_func=UserAPI.as_view('users'))
一个例子:
# app.py:
from flask import Flask, render_template, request, views # 导入相应模块
app = Flask(__name__) # Flask初始化
@app.route('/') # 定义路由
def hello_world(): # 定义视图函数
return render_template('index.html') # 渲染模板
class LoginView(views.MethodView): # 定义LoginView类
# 当用户通过get方法进行访问的时候执行get方法
def get(self): # 定义get函数
return render_template("index.html") # 渲染模板
# 当用户通过post方法进行访问的时候执行post方法
def post(self): # 定义post 函数
username = request.form.get("username") # 接收表单中传递过来的用户名
password = request.form.get("pwd") # 接收表单中传递过来的密码
if username == 'admin' and password == 'admin': # 如果用户名和密码是否为admin
return "用户名正确,可以登录!" # i f语句为真的话,返回可以登录信息
else:
return "用户名或密码错误,不可以登录!" # 否则,返回不可以登录信息
# 通过add_url_rule添加类视图和url的映射关系
app.add_url_rule('/login', view_func=LoginView.as_view('loginview'))
if __name__ == '__main__': # 当模块被直接运行时,代码将被运行,当模块是被导入时,代码不被执行
app.run(debug=True) # 开启调试模式
# index.html:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
div {
text-align: center;
}
.input {
width: 350px;
height: 40px;
margin: 10px auto;
}
.button {
background: #2066C5;
color: white;
font-size: 18px;
font-weight: bold;
height: 50px;
border-radius: 4px;
}
</style>
</head>
<body>
<div>
<form action="login" method="post">
<input type="text" class="input" name="username" placeholder="请输入用户名"><br>
<input type="password" class="input" name="pwd" placeholder="请输入密码"><br>
<input type="submit" value="登录" class="input button">
</form>
</div>
</body>
</html>
更详细的内容请参考官方文档Pluggable Views
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/98122.html