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. 九度OJ--Q1164

    import java.util.Scanner; /* * 题目描述: * 任意输入两个9阶以下矩阵,要求判断第二个是否是第一个的旋转矩阵,如果是,输出旋转角度(0.90.180.270),如果不是 ...

  2. php常见安全问题

    XSS攻击原理: XSS又叫CSS (Cross Site Script) ,跨站脚本攻击.它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会 ...

  3. tomcat web.log 系统日志记录文件过大问题修改

    目前各系统都是记录所有的日志,产生日志文件太大,按照如下设置修改log4j.properties文件:其中橙色部分为系统名称,例如water-scada系统,名称可以为scada. #Sun Jun ...

  4. HDU 4588 Count The Carries(数学统计)

    Description One day, Implus gets interested in binary addition and binary carry. He will transfer al ...

  5. ORACLE和SQL语法区别归纳

    数据类型比较类型名称 Oracle   SQLServer   比较字符数据类型  CHAR  CHAR  都是固定长度字符资料但oracle里面最大度为2kb,SQLServer里面最大长度为8kb ...

  6. Oracle入门书籍推荐

    作者:eygle |English [转载时请标明出处和作者信息]|[恩墨学院 OCM培训传DBA成功之道] 链接:http://www.eygle.com/archives/2006/08/orac ...

  7. http请求的过程

    http请求格式: http请求格式由四部分组成,分别是:请求行,请求头,空行,消息体,每个部分占一行. 请求行是消息体的第一行,由三部分组成,分别是:请求方法,请求资源的url,http的版本号. ...

  8. Session接口常用方法

    org.hibernate.Session接口 beginTransaction 开启事务 clear 清缓存 close 关闭session connection - 过时 获取Connection ...

  9. P1717 钓鱼

    题目描述 话说发源于小朋友精心设计的游戏被电脑组的童鞋们藐杀之后非常不爽,为了表示安慰和鼓励,VIP999决定请他吃一次“年年大丰收”,为了表示诚意,他还决定亲自去钓鱼,但是,因为还要准备2013NO ...

  10. [洛谷P4782]【模板】2-SAT 问题

    题目大意:有$n$个布尔变量 $x_1 \sim x_n$,另有$m$个需要满足的条件,每个条件的形式都是"$x_i$ 为$true/false$或$x_j$为$true/false$&qu ...