flask——3:路由与视图

路由、视图、模板配合才能完成较完整的请求响应过程。

前面简单了解了以上三者,这里将进一步介绍路由机制与视图。

一,函数视图

就像在创建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反转,它可以:

  1. 集中管理URL
  2. 避免相对路径的使用错误
  3. 给指定的函数构造 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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值