Flask视图高级技术

一、app.route与add_url_rule简介

  1.在Flask应用中,路由是指用户请求的URL与视图函数之间的映射,处理URL与函数之间关系的程序称为路由。HTTP请求的URL,Flask框架根据在路由表中匹配预定义的URL规则,找到对应的视图函数,并将视图函数的执行结果返回给服务器。

      通常URL组成如下:

            URL=传输协议+主机号+端口号+(目录)文件名; 传输协议一般是http或者https,主机号主要指服务(www)+域名。

      1)url_for(): 以视图函数名为参数,返回对应的URL;

   2) app.route: 将视图函数和URL绑定;

@app.route('/',endpoint='index')
def hello_world():
    return "hello world"

   上述代码实现了将URL'/' 与视图函数hello_world()的绑定,因为使用了endpoint参数,在使用url反转时就不能使用视图函数名,而是要用我们定义的URL名,即 url_for('index') 。

      3)add_url_rule:也是将视图函数和URL绑定;

       其中参数 rule:设置的URL

                      endpoint: 给URL设置的名称

                    view_func:指定视图函数的名称

from flask import Flask, render_template, request, redirect, url_for

app =Flask(__name__)

@app.route('/', methods=['POST', 'GET'],endpoint='index')
def hello_world():
    return "hello world!"
def my_test():
    return "my test!"
app.add_url_rule(rule='/test/',endpoint='test',view_func=my_test)
with app.test_request_context():
    print(url_for('test'))

if __name__ == '__main__':

    app.run( debug=True)

在上述代码中,视图函数为hello_world()和my_test(), 

app.add_url_rule(rule='/test/',endpoint='test',view_func=my_test) #定义了路由、endpoint
with app.test_request_context(): #构建了一个虚拟的请求上下文环境

注:1)在浏览器地址栏中直接输入地址是属于GET方法访问

       2)Flask是通过endpoint找到视图函数的

二、Flask类视图

    前面接触的视图都是函数,所以一般简称为视图函数;视图函数也可以基于类来实现,类视图的好处是支持继承,编写完类视图需要通过 app.add_url_rule(url_rule,view_func)来进行注册(类似java里面的抽象类)。Flask类视图一般分为标准类视图和基于调度方法的类视图。

    2.1、标准类视图

       1)标准类视图特点:

                必须继承flask.views.View。(父类中继承)

                必须实现dispatch_request方法,以后请求过来后,都会执行这个方法,这个方法的返回值相当于之前的视图函数。(在子类中使用)

               必须通过 app.add_url_rule(rule,endpoint,view_func)来做URL与视图的映射,view_func参数需要使用as_view类方法转换。

               如果指定了endpoint,那么在使用url_for反转时必须使用endpoint指定的值。

from flask import Flask, render_template, request, views
app =Flask(__name__)
class Ads(views.View):  #定义视图类Ads
    def __init__(self):  #实例化
        super().__init__()  #继承自__init__()方法
        self.context ={   #设置
            'ads': "这是一个视图类例子!"
        }

class Index(Ads):    #定义Index类,继承Ads
    def dispatch_request(self): #使用dispatch_request()方法,所定义类视图
        return render_template('index.html',**self.context) #渲染模板

class Login(Ads):
    def dispatch_request(self):  # V使用dispatch_request()方法,所定义类视图
        return render_template('login.html', **self.context)  # 渲染模板
class Register(Ads):
    def dispatch_request(self):  # 使用dispatch_request()方法,所定义类视图
        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, 在该函数中,返回一个元组作为Response对象;

 def __init__(self): 是一个初始化方法,__init__方法的第一个参数永远是self,表示创建的示例本身,可以在该方法的内部,将各种属性绑定到self,因为self就指向创建的示例本身;

其中,一个index.html如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    首页!{{ads}}
</body>
</html>

以下为实验结果

    

 

2.2、基于方法的类视图

     利用视图函数实现不同的请求执行不同的逻辑时比较复杂,需要在视图函数中进行判断,如果利用方法视图实现就比较简单。Flask提供另外一种类视图flask.views.MenthodView,对每个HTTP方法执行不同的函数。

from flask import Flask, render_template, request, views
app =Flask(__name__)
@app.route('/',methods=['get','post'])

def hello_world():
    return render_template('index.html')

class LoginView(views.MethodView):  #定义视图类Ads
    def get(self):
        return render_template('index.html')
    def post(self):
        username=request.form.get("username")
        password=request.form.get('pwd')
        if username=='admin' and password=='admin':
            return "correct!"
        else :
            return "error"
app.add_url_rule(rule='/login',view_func=LoginView.as_view('loginview')) #注意rule='/login',后面没有“/”

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

    注意:这里rule='/login' , 而不是rule= '/login/' , 如果写成后者会出错,估计是这里用到了提交表单,只能要求前者的写法。

   <body><!--body区域开始-->
   <div class="div1"><form action="login" method = "post"><!--表单开始-->
       <input type="text" class="input" name="username" placeholder="请输入用户名">
   	<input type="password" class="input"  name="pwd" placeholder="请输入密码">
       <input type="submit" value="登录"  class="input button"><!--定义登录submit-->
   </form></div><!--表单定义完毕-->
   </body>

三、Flask装饰器

       装饰器本质上是一个python函数,可以让其它函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值是一个函数对象。装饰器经常用于有切面需求的场景。比如插入日志、性能测试、事务处理、缓存和权限校验等场景。

      装饰器是解决这类场景的绝佳设计,有了装饰器,可以抽离大量与函数功能无关的雷同代码继续重用。

   1、装饰器的定义和基本使用

         1)例如场景:一个新闻站点,新闻列表页、详情页等都要求用户登录才能够浏览。下面定义的user_login()函数,实质就是一个装饰器。

def user_login(func): #定义函数,使用func接收函数作为参数
       def inner():#定义inner()函数
        print('登录操作')#打印输出
        func()#执行func函数
       return inner#返回inner函数,不是返回函数的结果

user_login(func):  使用func接收函数作为参数 ,定义了一个inner()函数

      2)新闻页函数,要求登录后才能访问

      

from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__) #Flask初始化
@app.route('/')#定义路由
def hello_world():#定义函数
       return 'Hello World!'#返回值
def user_login(func): #定义函数,使用func接收函数作为参数
    def inner():#定义inner()函数
        print('登录操作')#打印输出
        func()#执行func函数
    return inner#返回inner函数,不是返回函数的结果
@user_login#使用了装饰器
def news():#定义函数news
    print('这是新闻详情页')#打印输出
news();#调用news来执行

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

其中,news() : 先执行inner()函数,再执行func()函数,即为new()函数

四、蓝图

      随着业务代码的增加,将所有代码都放在单个程序文件中是非常不合适的。flask蓝图提供了模块化管理程序路由的功能,使程序结构清晰、简单易懂。

      一个程序执行文件中,如果功能代码过多,是不方便后期维护的。

     蓝图的定义:在蓝图被注册到应用后,所要执行的操作的集合。当分配请求时,Flask会把蓝图和视图函数关联起来,并生成两个端点之前的URL 。

         主路由视图函数app.py:

from flask import Flask  # 导入Flask模块
import news,products     #导入相应模块
app = Flask(__name__)  # 创建 Flask()对象: app
@app.route('/')   # 使用了蓝图,app.route() 这种模式就仍可以使用,注意路由重复的问题
def hello_world(): #定义函数
       return "hello my world !" #返回值
app.register_blueprint(news.new_list)  # 将news模块里的蓝图对象new_list注册到app
app.register_blueprint(products.product_list)  # 将products模块里的蓝图对象product_list注册到app
if __name__ == '__main__':
       app.run(debug=True)  # 调试模式开 启动服务器 运行在默认的5000端口

 news.py文件:

from flask import Blueprint#导入Blueprint模块
new_list = Blueprint('news', __name__)  # 创建一个blueprint对象。第一个参数可看做该blueprint对象的姓名
# 在一个app里,姓名不能与其余的Blueprint对象姓名重复
# 第二个参数__name__用作初始化
@new_list.route("/news")  # 将蓝图对象当做‘app’那样使用
def new():#定义函数news()
     return '这是新闻模块!'

products.py文件:

from flask import Blueprint#导入Blueprint模块
product_list = Blueprint('products', __name__)  # 创建一个blueprint对象。第一个参数可看做该blueprint对象的名字
# 在一个app里,对象名不能与其余的Blueprint对象名重复
# 第二个参数__name__用作初始化
@product_list.route("/products")  # 将蓝图对象当做‘app’那样使用
def product():
       return '这是产品模块!'

   

          视图函数的名称不能和蓝图对象的名称相同。蓝图的目的是实现各个模块的视图函数写在不同的py文件中。再主视图中导入分路由视图的模块,并且注册蓝图对象。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值