Flask开发:蓝图

引言

Flask中的蓝图(Blueprint)的作用就是将功能与主服务分开,比如说,你有一个图书管理系统。最开始的时候,只有一个查看图书列表的功能(show_book)模块,后来你又加入了一个添加图书的功能(add_book)模块, 然后又加入了一个删除图书的功能(del_book)模块,然后又加入了一个修改图书的功能(edit_book)模块。

在这个系统中,就可以将查看图书,修改图书,添加图书,删除图书的四个功能做成蓝图加入到图书管理系统中,本篇就会做一个这样的例子,但是首先我们要搞清楚什么是蓝图(Blueprint)。

蓝图(Blueprint)

A blueprint is an object that allows defining application functions without requiring an application object ahead of time. It uses the same decorators as Flask, but defers the need for an application by recording them for later registration.

蓝图是一个对象,它允许定义应用程序功能而无需提前使用应用程序对象。它使用与相同的修饰符Flask,但通过记录它们以供以后注册来满足对应用程序的需求。

上面这句话对于初学者有点难理解,转译一下大概就是可以把蓝图当成一个没有run方法的Flask对象,注册后就能使用。

具体一点:Blueprint 是一个存储视图方法的容器,这些视图方法在这个Blueprint 被注册到一个应用之后就可以被调用,Flask 可以通过Blueprint来组织URL以及处理请求,让应用实现模块化。

辅助文件说明

实现图书管理页面需要用到的组件代码及前端静态文件:

data.json 存储图书数据的json文件:

[
    {
        "id": "0",
        "title": "活着",
        "author": "余华"
    },
    {
        "id": "1",
        "title": "了不起的自己",
        "author": "程海贤"
    },
    {
        "id": "2",
        "title": "百年孤独",
        "author": "马尔克斯"
    },
    {
        "id": "3",
        "title": "社会心理学",
        "author": "戴维迈尔斯"
    }
    ......
]

data.py 提供处理data.json文件的常用接口:

import json, os

data_file = os.path.dirname(os.path.abspath(__file__))
filename = os.path.join(data_file, 'data.json')

# 保存图书数据
def sava_data(bookc):
    bookc = sorted(bookc,key=lambda x : int(x["id"]))
    with open(filename, "w", encoding="utf-8") as f:
        json.dump(bookc, f, indent=4, ensure_ascii=False)

# 读取图书数据
def open_data():
    with open(filename, encoding="utf-8") as f:
        book_data = json.load(f)
    bookx = book_data
    return bookx

# 添加图书数据
def add_data(book_dic):
    if book_dic["id"]=="":
        book_dic["id"]="None"
    bookx = open_data()
    bookx.append(book_dic)

    sava_data(bookx)

# 删除图书数据
def del_data(nid):
    bookx = open_data()

    for index, book in enumerate(bookx):
        if nid == str(book["id"]):
            bookx.pop(index)

    sava_data(bookx)

# 编辑图书数据
def edit_data(nid, book_dic):
    if book_dic["id"]=="":
        book_dic["id"]="None"
    bookx = open_data()
    for index, book in enumerate(bookx):
        if nid == str(book["id"]):
            bookx[index] = book_dic

    sava_data(bookx)

需导入的前端静态文件:

bootstrap-3.3.7/css/bootstrap.css
jQuery/jquery-1.10.2.js
bootstrap-3.3.7/js/bootstrap.js

前端页面show.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,
  initial-scale=1">
    <title>show_books</title>
    <link rel="stylesheet" type="text/css" href="/static/bootstrap-3.3.7/css/bootstrap.css">
</head>
<body>
<h1 class="text-center" style="margin-top: 50px">图书管理</h1>
<span data-toggle="modal" data-target="#myModal" data-whatever="添加图书" class="label label-primary"
      style="float: right;margin-right: 270px;font-size: 14px">
        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
        添加图书
</span>
<table class="table table-hover">
    <thead>
    <tr>
        <td>ID</td>
        <td>标题</td>
        <td>作者</td>
        <td>操作</td>
    </tr>
    </thead>
    <tbody>
    {% for foo in books %}
        <tr>
            <td>{{ foo.id }}</td>
            <td>{{ foo["title"] }}</td>
            <td>{{ foo["author"] }}</td>
            <td>
                <a data-toggle="modal" data-target="#myModal" data-whatever="编辑图书">
                    <span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
                </a>&nbsp;
                <a href="/del/{{ foo.id }}">
                    <span class="glyphicon glyphicon-remove-circle" aria-hidden="true">
                    </span>
                </a>
            </td>
        </tr>
    {% endfor %}
    </tbody>
</table>

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel"></h4>
            </div>
            <div class="modal-body">
                <form id="formx" class="form-horizontal" action="/add" method="post">
                    <div class="form-group">
                        <label class="col-sm-2 control-label">ID</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="id">
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">标题</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="title">
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">作者</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="author">
                        </div>
                    </div>
                    <div class="modal-footer">
                        <a href="/add" class="center-block">
                            <button type="submit" class="btn btn-primary">保存</button>
                        </a>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>
<script src="/static/jQuery/jquery-1.10.2.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.js"></script>
<script>
$('#myModal').on('show.bs.modal', function (event) {
  var button = $(event.relatedTarget);
  var recipient = button.data('whatever');
  var modal = $(this);
  modal.find('.modal-title').text(recipient);
  if (recipient === "编辑图书"){
      book_id = button.closest('tr').find('td').eq(0).text();
      book_title = button.closest('tr').find('td').eq(1).text();
      book_name =  button.closest('tr').find('td').eq(2).text();
      modal.find('.modal-body input[name="id"]').val(book_id);
      modal.find('.modal-body input[name="title"]').val(book_title);
      modal.find('.modal-body input[name="author"]').val(book_name);
      $("#formx").attr("action", "/edit/"+book_id);
  }else {
      modal.find('.modal-body input').val("")
  }
})
</script>
</body>
</html>

项目目录:
在这里插入图片描述

初识蓝图

首先创建一个查看图书列表功能模块的蓝图,对应项目目录文件show.py:

from flask import Blueprint,render_template # 导入 Flask 中的蓝图 Blueprint 模块
from books_management import data # 导入辅助数据处理的接口文件data.py


show_books = Blueprint("show",__name__)#实例化一个叫show_books的蓝图(Blueprint)对象

@show_books.route("/")# 蓝图中添加对象和路由的方法与在Flask对象中是一致的
def show_f(): # 直接将读取到的图书数据传递到前端
    return render_template("show.html",books=data.show_data())

然后注册,对应项目目录文件__init__.py:

from flask import Flask
from books_management import add,edit,delete,show


def create_app(): # 创建Flask对象
    app = Flask(__name__)
    
    app.register_blueprint(show.show_books)//注册show_books蓝图

    return app

在主程序中运行,对应项目目录文件app.py:

from books_management import create_app

app = create_app()

if __name__ == "__main__":
    app.run(debug=True) # 运行Flask对象

开启服务,然后访问 http://127.0.0.1:5000 查看一下成果吧:

什么链接都不要点,因为点啥都不好使,之后咱们一个一个的做
在这里插入图片描述
很明显,我们没有在Flask对象中添加路由,但是我们注册了有路由和视图函数的show_books蓝图对象

每个蓝图都可以为自己独立出一套template模板文件夹与static静态文件夹,如果不写则共享项目目录中的templates与static

注意:蓝图内部的视图函数及route不要出现重复,否则~你们自己试试吧

添加图书的蓝图

创建添加图书模块的蓝图,对应项目目录文件add.py:

from flask import Blueprint
from books_management import data
from flask import request,redirect

add_books = Blueprint("add", __name__)


@add_books.route("/add",methods=["GET","POST"]) 
def add_f():
    if request.method == "POST":
        book_dic = { # 字典用于存储从form表单传来的图书数据
            "id": request.form["id"],
            "title": request.form["title"],
            "author": request.form["author"]
        }
        data.add_data(book_dic) #交由添加图书的接口处理
    return redirect("/")

然后注册,对应项目目录文件__init__.py:

from flask import Flask
from books_management import add,edit,delete,show


def create_app(): # 创建Flask对象
    app = Flask(__name__)
    
    app.register_blueprint(show.show_books)#注册show_books蓝图
    app.register_blueprint(add.add_books)#注册add_books蓝图

    return app

启动,然后点击添加图书试试吧

| 前端原理解析

点击添加图书的span标签,可以启动Bootstrap模态框:

<span data-toggle="modal" data-target="#myModal" data-whatever="添加图书" class="label label-primary"
      style="float: right;margin-right: 270px;font-size: 14px">
        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
        添加图书
</span>

Bootstrap模态框实现:

<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="myModalLabel">添加图书</h4>
            </div>
            <div class="modal-body">
                <form id="formx" class="form-horizontal" action="/add" method="post">
                    <div class="form-group">
                        <label class="col-sm-2 control-label">ID</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="id">
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">标题</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="title">
                        </div>
                    </div>
                    <div class="form-group">
                        <label class="col-sm-2 control-label">作者</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" name="author">
                        </div>
                    </div>
                    <div class="modal-footer">
                        <a href="/add" class="center-block">
                            <button type="submit" class="btn btn-primary">保存</button>
                        </a>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>

form表单默认向action="/add"发送数据
在这里插入图片描述

修改图书的蓝图

创建修改图书模块的蓝图,对应项目目录文件edit.py:

from flask import Blueprint
from books_management import data
from flask import request,redirect
edit_books = Blueprint("edit", __name__)


@edit_books.route("/edit/<string:nid>",methods=["GET","POST"])
def edit_f(nid): # nid就是图书的ID
    if request.method == "POST":
        book_dic = { # 字典用于存储从form表单传来的图书数据
            "id": request.form["id"],
            "title": request.form["title"],
            "author": request.form["author"]
        }

        data.edit_data(nid,book_dic)# 交由编辑图书的接口处理

    return redirect("/")

然后注册,对应项目目录文件__init__.py:

from flask import Flask
from books_management import add,edit,delete,show


def create_app(): # 创建Flask对象
    app = Flask(__name__)
    
    app.register_blueprint(show.show_books)#注册show_books蓝图
    app.register_blueprint(add.add_books)#注册add_books蓝图
    app.register_blueprint(edit.edit_books)#注册edit_books蓝图

    return app

启动,然后点击编辑图书试试吧

| 前端原理解析

点击编辑图书的span标签,可以启动Bootstrap模态框:

<td>
    <a data-toggle="modal" data-target="#myModal" data-whatever="编辑图书">
     <span class="glyphicon glyphicon-edit" aria-hidden="true"></span></a>
</td>

由于模态框默认为添加图书,所以要用JavaScript进行处理:

<script>
$('#myModal').on('show.bs.modal', function (event) {
  var button = $(event.relatedTarget);
  var recipient = button.data('whatever');
  var modal = $(this);
  modal.find('.modal-title').text(recipient);
  if (recipient === "编辑图书"){
      book_id = button.closest('tr').find('td').eq(0).text();
      book_title = button.closest('tr').find('td').eq(1).text();
      book_name =  button.closest('tr').find('td').eq(2).text();
      modal.find('.modal-body input[name="id"]').val(book_id);
      modal.find('.modal-body input[name="title"]').val(book_title);
      modal.find('.modal-body input[name="author"]').val(book_name);
      $("#formx").attr("action", "/edit/"+book_id);
  }else {
      modal.find('.modal-body input').val("")
  }
})
</script>

上述js代码主要改变模态框的标题,获取点击事件所在行的表格内容,修改form表单中的action属性值为"/edit/"+图书ID
在这里插入图片描述

修改的功能也已经做完了,同学们自己尝试做一下删除吧

项目目录回顾:
在这里插入图片描述
__ init__.py:构建app的函数,并且将books_management中的各功能模块的蓝图注册进去
static:静态文件存放目录
templates:模板存放目录
data.py: 提供处理data.json文件的常用接口
data.json: 存储图书数据的json文件
app.py : 项目的启动文件

以上就是我们Flask小型应用的项目结构目录了,要牢记哦

更多可参考官方文档 蓝图

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值