Flask 路由、视图、模版、闪现详解

一、注册路由

1、定义

路由:指根据url定位到具体的类或者函数的程序,本质就是建立url跟程序之间的映射。flask中使用的路由被称之为注册路由

2、路由传参

2.1 动态传参

# 动态传参语法
@app.route(路径+/<参数名>/')
#例子
@app.route('/index/<id>/')
def index(id)
    print(id)
    return id

使用转换器进行对传参的类型进行限定

string 默认的数据类型,接收没有任何斜杆\ /的字符串
int 整型
float 浮点型
path 跟string类型类似,它可以接受斜杆/\
uuid uuid格式的字符串
any 可以指定多种路径

 

 

 

 

 

 

 

 

#使用方法
@app.route('/index/<int:id>/')
def index(id):
    return id

# any类型的用法、它可以指定多种路径
@app.route('/<any(user,admin):who>/<id>/')
def home(who,id):
    if who== 'user':
        return '这里是普通用户{}的主页'.format(id)
    else:
        return '这里是管理员{}的主页'.format(id)    

动态路由一般可以用来提高网站的曝光率

2.2 查询字符串传参(也就是?传参)

注意:request.args获取的是解析后的字典类型,request.query_string获取的是问号后的原生字符串。

http://127.0.0.1:5000/?name='hello'&age=18
@app.route('/')
def home():
    print(request.args)
    #>: ImmutableMultiDict([('name', "'hello'"), ('age', '18')])
    print(request.query_string)
    #>: b'name=%27hello%27&age=18'
    return '这是跟路径'

3、自定义动态路由过滤(转换器)

3.1 正则匹配

from flask import Flask, views, url_for
from werkzeug.routing import BaseConverter

app = Flask(__name__)

class RegexConverter(BaseConverter):
    """
    自定义URL匹配正则表达式
    """
    def __init__(self, map, regex):
        super(RegexConverter, self).__init__(map)
        self.regex = regex

    def to_python(self, value):
        """
        路由匹配时,匹配成功后传递给视图函数中参数的值
        """
        return int(value)

    def to_url(self, value):
        """
        使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
        """
        val = super(RegexConverter, self).to_url(value)
        return val
# 添加到flask中
app.url_map.converters['regex'] = RegexConverter
# 在路由中使用
@app.route('/index/<regex("\d+"):nid>')
def index(nid):
    print(url_for('index', nid='888'))
    return 'Index'

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

注意:必须继承werkzeug.routing 的BaseConverter类,regex属性指定路由过滤规则,app.url_map.converters本质就是一个字典

3.2 自定义动态路由过滤器处理动态路由

# -*-coding:utf-8 -*-
from flask import Flask,url_for
from werkzeug.routing import BaseConverter

app = Flask(__name__)

class ListConverter(BaseConverter):
    regex = '.*'
    def to_python(self, value):
        '''
        对动态参数进行处理
        :param value: 路由里的动态参数
        :return: 处理好的动态参数结果
        '''
        print(value) # a+b+c
        return value.split('+')
    def to_url(self, value):
        '''
        搭配url_for使用,对value进行处理
        :param value: url_for指定的动态参数
        :return:
        '''
        print('to_url:',value) #结果:to_url: ['a', 'b']
        return '+'.join(value)

app.url_map.converters['list']=ListConverter

@app.route('/test/<list:ids>/') #注意这里没有设置endpoint,所以默认是home
def home(ids):
    # 对http://127.0.0.1:5000/test/a+b+c/发起请求
    print('home:',ids) # 结果 ['a', 'b', 'c']
    print(url_for('home',ids=['a','b'])) #结果 /test/a+b/
    return 'home'

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

总结:to_python()方法是对动态路由的参数进行处理,to_url是对url_for()函数传入的动态参数进行处理

4、endpoint参数

4.1 endpoint 简介

endpoint是注册路由中的一个参数,也叫端点(类似函数的别名)通过url_for函数+endpoint参数值,可以反解出url

@app.route('/index11',endpoint='i')
def index():
    print(url_for('i')) #打印结果:/index11

4.2、对endpoint参数有关源码分析

def route(self, rule, **options):
    def decorator(f):
        # 1、先从options中获取endpoint值,如果没有,则赋值None给endpoint
        endpoint = options.pop("endpoint", None)
        # 2、将endpoint传到add_url_rule函数(也是注册路由的关键函数)中处理
        self.add_url_rule(rule, endpoint, f, **options)
        return f

    return decorator
def add_url_rule(self,rule,endpoint=None,view_func=None,
    provide_automatic_options=None,
    **options
    ):
    # 3、先判断endpoint是否为None  
    if endpoint is None:
        # 4、endpoint值为None的时候,调用_endpoint_from_view_func   
        endpoint = _endpoint_from_view_func(view_func)
    #4/7、 endpoint有值的时候,把它传给options    
    options["endpoint"] = endpoint
def _endpoint_from_view_func(view_func):
    # 5、用断言来判断函数是否为None,是则报错
    assert view_func is not None, "expected view func if endpoint is not provided."
    # 6、返回一个函数的的函数名
    return view_func.__name__

 5、add_url_rule(): 注册路由的第二种方式

def index():
    return '注册路由的另一种方式'

app.add_url_rule('/index/',endpoint('自定义名字'),view_func=index(函数地址)

6、注册路由中用到的参数

# ----------常用参数--------------
# @app.route()和app.add_url_rule参数
rule      #路由路径
view_func # 视图函数名称
endpoint  # 端点名字,用于url_for反向解析url
methods   # 允许请求的方式

# -----------其他参数---------------
# 1、对url是否加/是否有严格要求 
strict_slashes=Flase  #访问http://127.0.0.1/index和http://127.0.0.1/index/都可以
@app.route('/index', strict_slashes=True)  #仅可以访问http://www.xx.com/index

# 2、重定向 redirect_to
@app.route("/index",redirect_to='/home/') #当你访问index页面的时候,会跳到home页面去

# 3、为函数提供默认参数值
defaults = None #默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}
@app.route('/home',defaults={'k':'v'})
def home(k):
    print(k) # v
# 4、设置子域名 subdomain
from flask import Flask,url_for

app = Flask(__name__)
app.debug = True
'''
先在hosts设置域名解析(就是在本机的hosts文件上编辑上域名对应ip的关系) 
域名解析会先解析本地如果没有再解析dns服务器
C:\Windows\System32\drivers\etc\hosts

127.0.0.1 mark.com
127.0.0.1 admin.mark.com

'''
app.config['SERVER_NAME'] = 'mark.com:5000' # 这个代表访问这个域名的时候要访问5000端口

@app.route("/")
def index():
    return '设置域名成功'

@app.route("/admin_demo/",subdomain='admin')
def admin_demo():

    return '设置子域名成功'

'''
在浏览器中访问主域名
mark.com:5000/
在浏览器中访问子域名
admin.mark.com:5000/admin_demo/

注意:后面跟的path路径部分正常写
'''
if __name__ == '__main__':
    app.run(host='127.0.0.1',port=5000) # 测试服务器不稳定,尽量手动制定ip和端口

二、视图

1、视图函数

视图函数跟django的视图函数类似,只不过在视图函数中加装饰器有点不一样,flask中需要将装饰器卸载注册路由下面,视图函数上面,同时,装饰器内部要使用@wraps(func)方法,用于保护被装饰函数的属性

from flask import Flask, request
from functools import  wraps

app = Flask(__name__)

def login_verify(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        user_name = request.args.get('user')
        password = request.args.get('password')
        if user_name == 'mark' and password == '123':
            return func(*args,**kwargs)
        else:
            return '请登录'
    return wrapper

@app.route('/my_info/')
@login_verify
def my_info():
    return '个人信息页面'

2、视图类

2.1 标准类视图类

'''
1、继承flask.views.View
2、注册路由:app.add_url_rule(rule,endpoint,view_func)
--rule:路由地址
--endpoint: 端点
--view_func: 函数名称(不用加括号)
3、重写dispatch_request方法
'''
# -*-coding:utf-8 -*-
from flask import Flask,views,url_for

app=Flask(__name__)

class S_Test(views.View):
    def dispatch_request(self):
        print(url_for('List')) #/stest
        return '这是标准视图类'
'''
注意:如果设置了endpoint,那么使用url_for反转的时候,就要用endpoint的值
     如果没有,则可以直接用as_view中的指定的视图名字来作为反转
     as_view('视图名字')
'''
app.add_url_rule('/stest',view_func=S_Test.as_view('List'))
if __name__=='__main__':
    app.run(debug=True)

2.2 基于调度方法的视图类

'''
1、继承flask.views.MethodView
2、指定支持请求类型 methods=[]
3、指定使用哪些装饰器 decorators = []
4、写相应的请求函数
5、注册路由
'''
from flask import Flask,views,url_for
from functools import wraps

app=Flask(__name__)

class Test(views.MethodView):
    methods = ['GET',"POST"]  #设置可以接收的请求方法
    decorators = [auth]  # 指定装饰器,注意不能添加单引号或者双引号
    # get请求方法
    def get(self):
        return '这是get请求方法'
    # post请求方法
    def post(self):
        return '这是post请求方法'
# 同样,如果没有指定endpoint,url_for反转的时候,同样是使用as_view中的name值
app.add_url_rule('/test',view_func=Test.as_view(name='test1'))
if __name__=='__main__':
    app.run(debug=True)

三、模板引擎

1、概述

模版引擎:指实现视图的业务逻辑和返回给前端的页面逻辑分离的工具。

作用:实现业务逻辑和页面逻辑的分离,实现动态的去渲染页面

模版路径配置,可以在Flask类的template_folder参数设置

app = Flask(__name__,template_folder='模板位置')

app =Flask(__name__)
app.template_folder='模版位置'

2、模版传参

# 第一种,在render_template中把参数传过去
@app.route('/')
def index():
    return render_template('index.html',name='hello',age=18)

# 第二种,把参数放在字典中,将字典传递过去
@app.route('/')
def index():
    context_dict={
        'name':'hello',
        'age':18
    }
    return render_template('index.html',context=context_dict)
# 第三种,将字典打散传递过去
return render_template('index.html',**context_dict)

# ------------前端对接收到参数的处理--------------------
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    # 参数关键词
    {{ name }}
    # 字典参数
    {{ context.name }}
    {{ context.get('age') }}
    {{context['name']}}
</body>
</html>

3、模板引擎使用url_for

注意:url_for在模板中用法跟在视图函数的用法一样,没有指定endpoint,就使用函数名,指定了,就使用endpoint的值进行反转

# 例子
@app.route('/index')
def index():
    return render_template('index.html')
@app.route('/home',endpoint='h')
def home():
    return render_template('index.html')

# html文件
<a href="{{ url_for('h') }}">home</a>
<a href="{{ url_for('index') }}">index</a>
#这句会报错,因为home函数的路由已经设置了endpoint
<a href="{{ url_for('home') }}">home1</a> 

4、jinja2控制语句使用

# 控制语句都是以{% ... %} 开始 ,以{ %end...% }结束

4.1 逻辑语句和if 语句

'''
判断: >、<、<=、==、!=
逻辑:and、or、not、()
'''
{ % if age>18 %}
    ...
{% elif age ==9 %}
    ...
{% else %}
    ...
{%endif %} #表示结束判读

4.2 循环语句和for循环

# 遍历列表,可迭代对象,字典等
{% for dict in d %}
     ...
{% else %}
     ... # 遍历没有内容,才会执行else,for else逻辑在python是没有的
{% endfor %}
# 反转遍历
{% for dict in d | reverse %}
#------------ for 常用循环变量--------------
loop.index     #当前循环的索引(从1开始)
loop.index()   #当前循环的索引(从0开始)
loop.first       #是否是第一次循环,是返回True,否则返回Flase
loop.last       #是否是最后一次循环,是返回True,否则返回Flase
loop.length    #总共可以循环的次数 / 迭代器的长度

# 例子
 {% for college in colleges %}
      {% if loop.first %}
<tr style="background: blue">
{% elif loop.last %} <tr style="background: yellow "> {% else %} <tr> {% endif %} <td>{{ loop.index }}</td> <td>{{ loop.index0 }}</td> <td>{{ college.name }}</td> <td>{{ loop.length }}</td> </tr> {% endfor %}

5、静态文件在模板中的使用

{{ url_for('static',filename='相对于static文件夹的路径') }}
<!DOCTYPE html>
<html lang="en">
<head>
 ...
    <script src="{{ url_for('static',filename='js/demo.js') }}"></script>    
</head>
....

6、模板继承

定义一个基模版,在基模版中定义一些block块,以便给子模版实现自己的功能

# 1、基模版parent.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
# top是自己定义的变量名
{% block top %}
   <p>我是父模版</p>
{% endblock %}
</body>
</html>
# 2、子模板son.html继承parent.html
{% extends 'parent.html' %}
{% block top %}
    {{ super() }}  #表示继承父模板中的本块的代码
<p>我继承了parent模版</p>
{% endblock %}

四、闪现

1 定义

闪现:flask提供的一个简单的方法,用来向用户反馈信息,本质是将信息放在session中,必须设置secret_key,下次请求的时候,再从session中获取。

注意:闪现有效期只有一次,当下一次请求获取闪现的信息后,它就失效了

2 用法

from flask import Flask,flash,make_response,get_flashed_messages
# 需要导入flash、get_flashed_messages 用来设置和获取闪现值
app=Flask(__name__)
app.secret_key='shanxian'

@app.route('/')
def home():
    flash('欢迎来到首页')  #设置闪现值
    return 'index'

@app.route('/index')
def index():
    a=get_flashed_messages() #获取闪现值
    return 'index11'

前端获取闪现信息

{% with messages= get_flashed_messages() %} # 获取所有闪现信息,返回的是列表
    {% for m in messages %}
    <li>{{ m }}</li>
    {% endfor %}
{% endwith %}

3 分类闪现

默认分类是:message

#1、设置:
flash('hello',category='test') 
#
flash('hello','test')
# 2、取值,获取所有闪现信息的类别和内容
res=get_flashed_messages(with_categories=True)

# ------------前端获取(注意with_categories=true别忘记设置)---------------
{% with messages= get_flashed_messages(with_categories=true) %} # 获取所有闪现信息,返回的是列表
    {% for c,m in messages %}
    <li>{{ m }},{{ c }}</li>
    {% endfor %}
    {{ messages }}
    {% endwith %}
''' 结果如下:c是分类,m是闪现信息
test111,error
test222,tes
test333,test3
[('message', '欢迎来到首页'), ('error', 'test111'), ('tes', 'test222'), ('test3', 'test333')]
'''

4 过滤闪现信息( category_filter参数)

#-----------后端视图函数过滤-----------------
#默认category_filter =message
get_flashed_messages(category_filter=['类名'])

# -----------前端过滤闪现信息--------------
{% with messages= get_flashed_messages(category_filter=['test']) %} # 获取test类的闪现信息,返回的是列表
    {% for m in messages %}
    <li>{{ m }}</li>
    {% endfor %}

{% endwith %}

 

posted @ 2021-01-25 15:46  NQ31  阅读(319)  评论(0编辑  收藏  举报