Day 21 Flask Blueprint

前面说那麽多次以後会遇到大型专案会怎样怎样的,所以现在就要来说一下大型专案长怎样,如何将大型专案拆解开来看,让你不会拿到一大包东西完全不知如何下手。

话说因为 Flask 本身就是小框架,也没太多重要的或常用的东西可以讲;再加上我是想把 Flask 本体讲完再讲其他的啦,所以这篇算是有关 Flask 本体的最後一篇了。下一篇就会进入到 Flask 插件的部分(是说上一篇其实就有讲到插件了)。

Blueprint

如果网站架构持续运作了好几年,中间不断地修修改改,功能越来越多,架构越来庞大,将全部的路由都放在一个档案里面会造成维护上的困难,所以势必要将不同功能的路由拆成不同档案,以利维护。

而 Blueprints 是 Flask 提供的将不同功能的路由模组化管理的方式,不过路由是分开了,那前端视图跟静态文件呢?

如果不做设定,前端视图跟静态文件还是在 templatesstatic 里面,这样的优点是不同模组间能够套用同样的父视图(base.html 那个东东);而如果想要不同模组间可以有不同的视图,也能够分开摆放(也可以一部份分开,一部分放一起)。

位置统一

那就直接来看如何使用吧。让我们拿前面的架构再来改一下:

ithome
├── account  # 取个有意义的名字
│   └── api.py  # 随便取个名字
├── static
│   └── logo.png
├── templates
│   ├── account  # 它改个有意义的名字
│   │   ├── home.html
│   │   ├── login.html
│   │   └── settings.html
│   ├── base.html
│   ├── index.html
│   └── page_not_found.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock

然後将 app.py 里面的 home, login, settings 搬进去 account -> api.py 里面,再各加上几行。

然後因为移动了 index.htmlpage_not_found.html,还有改了 res 的资料夹名称,所以有关 render_template 的都需要改一下;以及路由需要修正一下。

app.py 里面应该剩这样:

from flask import Flask, render_template, make_response


# 这个 app 是 api.py 里面的 app,建议改个有意义的名字,同样都叫 app 是我懒得改
# 如果名称冲突到,可以使用 as 来取个昵称。
from account.api import app as account
from configs import config


app = Flask(__name__)
app.config.from_object(config.DevelopmentConfig)

# 注册 blueprint
app.register_blueprint(account)

# 这边的 app 是上面 Flask 的 app
@ app.route('/')
def index():
    return render_template('index.html')


''' 应该还有一些其他的东西,不过这里没有要用到,注解掉或删掉都没关系 '''


@ app.errorhandler(404)
def page_not_found(error):
    response = make_response(render_template(
        'page_not_found.html', error=error), 404)

    return response


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

前面的那三个路由搬到 api.py 里面,有关 render_template 的记得改一下。

# 新增这行
from flask import Blueprint, redirect, request, render_template, make_response, url_for


# 还有新增这行,同样叫 app 只是我懒得改,建议还是改有意义的名字。
app = Blueprint('account', __name__)


@app.route('/home', methods=['GET'])
def home():
    if 'username' in request.cookies:
        user = request.cookies.get('username')

    return render_template('account/home.html', username=user)


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        response = make_response(render_template('account/login.html'))
    elif request.method == 'POST':  # 表单送出後会到这里
        account = request.values.get('username', None)
        # 验证是否有这个使用者以及密码是否正确,生出验证结果 auth_result
        auth_result = 'success'  # 假设成功
        ''' 建立回应 '''
        if auth_result == 'success':  # 如果都正确
            response = make_response(redirect(url_for('account.home')))

            response.set_cookie('username', account)  # 先使用 Cookie 就好
        else:  # 如果错误
            response = make_response(redirect(url_for('account.login')))
    else:
        response = make_response(redirect(url_for('index')))

    return response


@app.route('/settings', methods=['GET'])
def settings():
    if 'username' in request.cookies:
        user = request.cookies.get('username')

    return render_template('account/settings.html', username=user)

改到这里就差不多了,如果在 .html 里面有使用到 url_for 的要记得改一下。例如 url_for('login') 要改成 url_for('account.login') ,前面加 Blueprint 中的第一个参数还有英文句号就 OK 了(还有不是那个 Blueprint 下的路由前面不要乱给他加名称,不要乱认亲)。

如果要改的都有改到的话,这几个功能应该跟移动之前是差不多的,不过这几个功能就分开来了,在维护时也能更快、更轻松的维护。

位置分开

如果要将前端视图与静态文件分开,首先至少要将它们搬到相应的位置对吧。

ithome
├── account
│   ├── static_account
│   │   └── logo.png
│   ├── templates_account
│   │   ├── account  # 因为我不想改 render_template,所以就留着它了。
│   │   │   ├── home.html
│   │   │   ├── login.html
│   │   │   └── settings.html
│   │   └── base.html
│   └── api.py
├── static
│   └── logo.png
├── templates
│   ├── base.html
│   ├── index.html
│   └── page_not_found.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock

搬完之後,再到 api.py 设定新的前端视图与静态文件位置,

api.py

from flask import Blueprint, redirect, request, render_template, make_response, url_for


app = Blueprint('account', __name__, static_folder='static_account',
                static_url_path='/img', template_folder='templates_account',
                url_prefix='/account')


@app.route('/home', methods=['GET'])
def home():
    if 'username' in request.cookies:
        user = request.cookies.get('username')

    return render_template('account/home.html', username=user)


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        response = make_response(render_template('account/login.html'))
    elif request.method == 'POST':  # 表单送出後会到这里
        account = request.values.get('username', None)
        # 验证是否有这个使用者以及密码是否正确,生出验证结果 auth_result
        auth_result = 'success'  # 假设成功
        ''' 建立回应 '''
        if auth_result == 'success':  # 如果都正确
            response = make_response(redirect(url_for('account.home')))

            response.set_cookie('username', account)  # 先使用 Cookie 就好
        else:  # 如果错误
            response = make_response(redirect(url_for('account.login')))
    else:
        response = make_response(redirect(url_for('index')))

    return response


@app.route('/settings', methods=['GET'])
def settings():
    if 'username' in request.cookies:
        user = request.cookies.get('username')

    return render_template('account/settings.html', username=user)

Blueprint 一样有着 static_folderstatic_url_pathtemplate_folder ,用法也跟 Day 17 一样。而 url_prefix 是什麽呢?

先来看看不加 url_prefix 会发生什麽事。

再来看看加了 url_prefix 会发生什麽事。

有注意到 url 的变化吗?就是在这个 Blueprint 里面的路由都加上 url 前缀。

那麽就大概这样,有关 Flask 本体大概就这样就结束了,下一篇开始就是 Flask 的插件了。

大家掰~掰~


<<:  Day23 - 将台湾证券交易所的每日收盘行情存入 DB

>>:  Day21-TypeScript(TS)的函式(Function) Part1

从0开始!Python 数据分析(1)|环境安装

我使用Anaconda帮我们管理套件以及不同的开发环境,让程序码可以在特定套件下执行,还可以在不同环...

Oracle 1Z0-082 Practice Exam 2021

**Actual Oracle 1Z0-082 Practice Exam - Easiest Wa...

IT铁人DAY 1-进入物件导向世界前的心理准备

  在开始之前,还是很惊讶自己有天可以在这里写文章,分享自身所学的IT技术,提供给大家参考。那其实我...

CSS 定位属性(DAY15)

这篇文章会介绍利用CSS定位的属性来控制html元素的位置,在之前的文章中有利用过padding和m...

Linux网络诊断工具 mtr

MTR是Linux平台上一款非常好用的网络诊断工具,或者说网络连通性判断工具,集成了tracerou...