1.add_url_rule和app.route原理剖析

from flask import Flask
app = Flask(__name__)

# 下面是我们定义一个路由和对应视图的常用方法
'''
@app.route(r"/index")
def index():
    return "index"
'''
# 这种方法等价于
def index():
    return "index"

app.add_url_rule(r"/index", view_func=index)
# 这种方式同样可以将路由和视图函数绑定在一起

  

from flask import Flask, url_for
app = Flask(__name__)

def index():
    return "index"

# 在add_url_rule中还有一个endpoint参数,这个参数也是通过url_for来使用的
app.add_url_rule(r"/index", view_func=index, endpoint="satori")

@app.route(r"/mashiro")
def mashiro():
    # 如果我们此时想获取index函数对应的路由,那么不能通过index来获取
    # url_for()中不可以传index,而是要传endpoint
    return url_for("satori")

if __name__ == '__main__':
    app.run(host="localhost", port=8888)

  

from flask import Flask, url_for
app = Flask(__name__)

# 我们在定义的时候也可以指定一个endpoint
# 如果没指定,那么默认使用函数进行url的反向解析,如果指定了,则使用endpoint。
# 但是add_url_rule则必须使用endpoint
@app.route(r"/satori", endpoint="aaa")
def satori():
    return "satori"

@app.route(r"/koishi")
def koishi():
    return url_for("aaa")
# 显然访问koishi就会在页面上显示相应的信息,并且url_for不能单独定义在外面,否则报错
# 如果我想在不访问页面的情况下就获取呢?
with app.test_request_context():
    print(url_for("aaa"))

if __name__ == '__main__':
    app.run(host="localhost", port=8888)

  

其实app.route本质上还是调用了app.add_url_rule,我们可以看一下源码

def route(self, rule, **options):
    # 首先route是一个装饰器,当我们往route里面传参的时候,会先执行这个函数
    # 返回一个decorator,然后装饰视图函数
    # endpoint就是我们在route中传的endpoint,没有传,就是None
    # 然后调用self.add_url_rule,将参数按照相应顺序传进去
    def decorator(f):
        endpoint = options.pop('endpoint', None)
        self.add_url_rule(rule, endpoint, f, **options)
        return f

    return decorator

  

2.标准类视图

from flask import Flask, views
app = Flask(__name__)

# 除了视图函数,我们也可以使用视图类
# 但是使用类,需要注意一点,那就是定义路由的时候,不能够使用装饰器的方式,要通过add_url_rule的方式
class Myview(views.View):
    # 定义一个视图类,这个类必须要继承views.View
    # 然后实现其内部的一个方法,这个方法必须实现,是专门用来处理请求的
    def dispatch_request(self):
        return "这是一个视图类"

# 将类和路由组合起来,view_func则是视图类调用as_view()方法的返回值,返回的是一个函数
# as_view的参数随便传一个就行,关于endpoint,如果不写,那么在反向解析的时候,使用as_view里面传入的参数
app.add_url_rule(r"/first_view", view_func=Myview.as_view("first_view"))

if __name__ == '__main__':
    app.run(host="localhost", port=8888)

  

3.基于调度方法的类视图

from flask import Flask, views
app = Flask(__name__)

class Satori(views.MethodView):
    # 定义的类要继承自views.MethodView
    def get(self):
        return "get"

    def post(self):
        return "post"

# 此时有点类似于tornado,当get请求到来,就触发get方法,post请求触发post方法
# 当然  同样需要注册
app.add_url_rule(r"/satori", view_func=Satori.as_view("satori"))

if __name__ == '__main__':
    app.run(host="localhost", port=8888)

  

我们可以做一个登录界面,如果输入正确那么返回页面,输入错误返回提示:用户名或者密码错误

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login" method="post">
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>密码</td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td></td>
                <td><input type="submit" name="提交"></td>
            </tr>
        </table>
        {% if error %}
                    <p style="color: red">{{error}}</p>
        {% endif %}
    </form>
</body>
</html>

    

from flask import Flask, views, request, render_template
app = Flask(__name__)

class Index(views.MethodView):

    def get(self):
        return render_template("1.html")

    def post(self):
        name = request.form.get("username")
        passwd = request.form.get("password")
        if name == "satori" and passwd == "123":
            return "欢迎来到古明地觉的避难小屋"
        return render_template("1.html", error="用户名或密码错误")

app.add_url_rule("/login", view_func=Index.as_view("login"))

if __name__ == '__main__':
    app.run(host="localhost", port=8888)

  

4.类视图中使用装饰器

先来一个基于普通函数视图的

from flask import Flask, views, request, render_template
from functools import wraps
app = Flask(__name__)

def deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        username = request.args.get("username")
        password = request.args.get("password")
        if username == "satori" and password == "123":
            return func(*args, **kwargs)
        else:
            return "请输入正确的用户名或密码"
    return wrapper

@app.route("/")
@deco
def hello():
    return "hello world"

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

  

  

基于类视图的装饰器

from flask import Flask, views, request, render_template
from functools import wraps
app = Flask(__name__)

def deco(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        username = request.args.get("username")
        password = request.args.get("password")
        if username == "satori" and password == "123":
            return func(*args, **kwargs)
        else:
            return "请输入正确的用户名或密码"
    return wrapper

# 使用类装饰器非常简单,flask都为我们考虑好了
class Hello(views.View):
    # decorators不能变,然后将装饰器以列表或者元组的形式进行赋值
    decorators = [deco]

    def dispatch_request(self):
        return "hello satori"
app.add_url_rule("/", view_func=Hello.as_view("hello"))

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

  

5.蓝图的基本使用

蓝图,和我们平常说的宏伟蓝图的蓝图有区别,flask的蓝图是为了将解耦,我们之前的所有程序都写在一个py文件里面,然而一旦程序代码多了,就显得很乱,所以需要分层解耦。

代码结构:

  

book.py

from flask import Blueprint

# 第一个参数是py文件名,这个时候就不能使用Flask了
book_app = Blueprint("book", __name__)

@book_app.route("/book/gone")
def gone():
    return "gone"

movie.py

from flask import Blueprint

# 第一个参数是py文件名
movie_app = Blueprint("movie", __name__, url_prefix="/movie")
# 如果加上了url_prefix,那么在访问的时候必须要加上url_prefix

@movie_app.route("/kiminonawa")
def kimi():
    return "你的名字"

start.py

from flask import Flask
# 将app导入进来
from blueprint.movie import movie_app
from blueprint.book import book_app

app = Flask(__name__)

# 然后进行注册
app.register_blueprint(movie_app)
app.register_blueprint(book_app)

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

  

  

6.蓝图中模板文件寻找规则

首先我们一开始的templates文件夹是毫无疑问可以的

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>我是主目录templates里的html文件</h2>
</body>
</html>

  

from flask import Blueprint, render_template

# 第一个参数是py文件名,这个时候就不能使用Flask了
book_app = Blueprint("book", __name__)

@book_app.route("/book/gone")
def gone():
    return render_template("1.html")

 

但是如果我不想在templates文件夹里面找呢?那么可以单独指定文件夹

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h2>我是blueprint下的666文件里面的html</h2>
</body>
</html>

  

from flask import Blueprint, render_template

# 可以指定template_folder,这个文件夹是相对于当前文件所在路径来说的来说的
# book.py在blueprint文件夹下,所以我在当前文件夹下创建一个名为666的文件夹
# 那么寻找模板就会到blueprint的666文件夹下寻找
book_app = Blueprint("book", __name__, template_folder="666")

@book_app.route("/book/gone")
def gone():
    return render_template("satori.html")

  

  

 模板文件寻找方式,会先到templates文件夹里面去找。如果没有,再去我们蓝图指定的文件夹里找。也就是说,如果我在templates文件里也定义了一个satori.html,那么会找templates的satori.html。

7.蓝图中静态文件寻找规则

和模板一样,flask默认会在主项目的static文件里面去寻找

如果我在blueprint里面定义了一个bl_static,我们才能让模板找到这里的css呢?

h2{
    color: aquamarine;
}

  

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="{% url_for('book.static', filename='1.css') %}">
</head>
<body>
    <h2>我是主目录templates里的html文件,但是我要找蓝图里面的css</h2>
</body>
</html>

  

from flask import Blueprint, render_template

# 这里指定了static_folder="bl_static",那么这个静态文件查找就是相对于当前文件所在路径的bl_static
# 但是我们flask在查找的时候默认是当前主项目的static,也就是和templates同目录的static
# 所以我们在html模板中指定的是,url_for('book.bl_static',filename='1.css')而不是url_for('bl_static',filename='1.css')
# 由于我们指定了book.bl_static,那么flask就会找到我们的蓝图book,而我们在book.py中定义了static_folder
# 那么flask就会去我们在book.py中指定的static_folder去找静态文件。如果不加book,那么还是会去项目的static文件夹去找
# 并且我想说的是,即便我们指定了蓝图,也和模板一样,默认到当前主项目的静态目录去找,找不到再去蓝图指定的静态目录里去找
# 如果这里定义的是static不是bl_static的话,那么是找不到的。
# 因为我们主程序的static_folder就是static,因此如果两者名字一样,就不会再来蓝图指定的静态目录里面找了
# 因此不要将主项目的静态目录和蓝图里的静态目录写成一样的
book_app = Blueprint("book", __name__, template_folder="666", static_folder="bl_static")

@book_app.route("/book/gone")
def gone():
    return render_template("1.html")

  

8.url_for翻转蓝图注意事项

如果我想获取蓝图中的url怎么办呢?

老规矩,我想在start.py中获取gone的url,如果两个方法都在主程序中,毫无疑问一个url_for("gone")就搞定了,但是现在其中一个方法在蓝图中,还可以这样吗?我们来试一下

from flask import Flask, url_for
# 将app导入进来
from blueprint.movie import movie_app
from blueprint.book import book_app

app = Flask(__name__)

# 然后进行注册
app.register_blueprint(movie_app)
app.register_blueprint(book_app)

@app.route('/get')
def get():
    return url_for("gone")

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

  

因此需要指定蓝图

@app.route('/get')
def get():
    return url_for("book.gone")

  

同理我们在模板中使用url_for也需要指定蓝图,url_for在模板和py文件中的使用方法是一样的。并且即使在同一个蓝图,要反响解析url,也需要指定蓝图

9.子域名实现详解

我新建了一个cms.py

from flask import Blueprint
# 指定了一个subdomain,那么以后就可以通过子域名访问,即cms.
cms_bp = Blueprint("cms", __name__, subdomain="cms")

# 这里的/index,我们是通过localhost:port/index访问
# 那么以后就可以使用cms.localhost:port/index访问,当然还要隐藏问题,我们会说
@cms_bp.route('/index')
def index():
    return "欢迎欢迎,热烈欢迎"

  

from flask import Flask, url_for
# 将app导入进来
from blueprint.movie import movie_app
from blueprint.book import book_app
from blueprint.cms import cms_bp

app = Flask(__name__)

# 然后进行注册
app.register_blueprint(movie_app)
app.register_blueprint(book_app)
app.register_blueprint(cms_bp)

# 如果现在执行的话,那么理论上要通过cms.localhost:8888或者cms.127.0.0.1:8888/index访问
# 但是不可以,因为ip地址是不可以有子域名的,所以我们需要配置一下。就像我们购买域名,然后映射到我们服务器的ip地址上
# 所有和配置相关的都放在app.config这个字典下面
# 我们这里是测试,所以就直接使用本地就可以,我们希望在访问京东的时候能够访问到我们本地
# 所以我们还需要都hosts文件里面配置一下
'''
127.0.0.1 jd.com
127.0.0.1 cms.jd.com
'''
# 那么以后在访问jd.com:8888,就会访问我们本机
app.config["SERVER_NAME"] = 'jd.com:8888'

@app.route('/index')
def index():
    return "欢迎,热烈欢迎"

if __name__ == '__main__':
    app.run(host="localhost", port=8888, debug=True)

  

  

  

3.flask视图进阶的更多相关文章

  1. Flask视图函数报fmalformed url rule错误的原因

    Flask视图函数报fmalformed url rule错误,原因可能是包含中文字符了 把标点符号都重新写一遍英文格式的,可能就不会报这个了

  2. Django 2.0 学习(07):Django 视图(进阶-续)

    接Django 2.0 学习(06):Django 视图(进阶),我们将聚焦在使用简单的表单进行处理和精简代码. 编写简单表单 我们将用下面的代码,来替换之前的detail模板("polls ...

  3. Flask 视图

    写个验证用户登录的装饰器:在调用函数前,先检查session里有没有用户 from functools import wraps from flask import session, abort de ...

  4. flask 视图函数的使用

    flask框架 视图函数当中 各种实用情况简单配置 1 建立连接 2 路由参数 3 返回网络状态码 4 自定义错误页面 5 重定向 6 正则url限制 和 url 优化 7 设置和获取cookie # ...

  5. Flask 视图,中间件

    视图 FBV def index(nid): """ 请求相关信息 request.method # 请求方式 request.args # get 方式的参数获取 re ...

  6. flask 电子邮件进阶实践-用模板发送163邮件

    电子邮件进阶实践 下面来学习构建邮件的HTML正文,并使用模板组织内容. 一封电子邮件的正文可以是纯文本(text/plain),也可以是HTML格式的文本(text/html).处于全面的考虑,一封 ...

  7. Flask视图函数与普通函数的区别,响应对象Response

    视图函数与普通函数看似没什么区别,其实他们的返回值上有着很大的区别. from flask import Flask app = Flask(__name__) @app.route('/hello' ...

  8. Flask 视图,模板,蓝图.

    https://www.cnblogs.com/wupeiqi/articles/7552008.html 1. 配置文件 from flask import Flask app =Flask(__n ...

  9. Flask视图函数与模板语法

    1.Django中的CBV模式 ​ 2.Flask中的CBV和FBV def auth(func):     def inner(*args, **kwargs):         result =  ...

随机推荐

  1. [GraphSAGE] docker安装与程序运行

    安装Docker与程序运行 1. requirements.txt Problem: Downloading https://files.pythonhosted.org/packages/69/cb ...

  2. sed-awk命令详解

      第2章 ***********sed***********. 1目  录 2.1 -------sed命令小结及小结图---- 1 2.2 -------第几行---------- 2 2.3 - ...

  3. 学习bash——环境配置

    一.环境配置文件的重要性 Bash在启动时直接读取这些配置文件,以规划好bash的操作环境. 即使注销bash,我们的设置仍然保存. 二.login shell 通过完整的登录流程取得的bash,称为 ...

  4. 在C/C++程序中打印当前函数调用栈

    前几天帮同事跟踪的一个程序莫名退出,没有core dump(当然ulimit是打开的)的问题.我们知道,正常情况下,如果程序因为某种异常条件退出的话,应该会产生core dump,而如果程序正常退出的 ...

  5. struts标签中的select

    <!-- Struts下拉列表标签: name="deptId" 下拉列表标签的名称(服务器根据这个名称获取选择的项的实际的值value值) headerKey 默认选择项的 ...

  6. 【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树的直径/LCA/树的点分治

    题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F ...

  7. JAVA 异常处理的认知学习过程

    没有异常处理 学生时代,我编写的java代码中,很少会有try catch.最主要的原因如下: 应用的规模很小 没有不确定因素 代码可控性高 如果规模小,往往就没有复杂的逻辑链路,整个软件的分层也很浅 ...

  8. Netscaler GSLB的主备数据中心解决方案

    Netscaler GSLB的主备数据中心解决方案 http://blog.51cto.com/caojin/1898182 GSLB的主.备数据中心解决方案思路: 其实这只是多数据中心的一个特例而已 ...

  9. [Leetcode] plus one 加一

    Given a number represented as an array of digits, plus one to the number. 题意:给定数以数组的形式存储,然后计算该数加1的值. ...

  10. 洛谷 P1502 窗口的星星 解题报告

    P1502 窗口的星星 题目背景 小卡买到了一套新房子,他十分的高兴,在房间里转来转去. 题目描述 晚上,小卡从阳台望出去,"哇~~~~好多星星啊",但他还没给其他房间设一个窗户, ...