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小型應用的項目結構目錄了,要牢記哦

更多可參考官方文檔 藍圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章