flask框架--flask項目之模塊划分


1、簡單拆分:模型,路由,配置
2、循環依賴問題
3、使用裝飾器解決路由模塊划分問題
4、使用藍圖划分模塊

 

flask框架--數據庫ORM框架flask-sqlalchemy

  我們學習Flask框架,是從單個文件開始,所有的代碼都寫在一個文件中,包括定義路由、視圖函數、定義模型等。但這顯然存在一個問題,隨着業務代碼的增加,將所有代碼都放在單個程序中,是非常不合適的。這不僅會讓代碼閱讀變得困難,而且會給后期維護帶來麻煩。本文基於上面這篇文章第8節的圖書demo,進行模塊划分(將db_demo.py拆開)

1、簡單拆分:模型,路由,配置    <--返回目錄

  將db_demmo.py拆分:將模型定義拆分為Author和Book;將路由定義拆分到route.py;將flask的app對象,和 SQLAlchemy的db對象拆分到app.py(方便其他模型引用app和db對象);配置放到configs.py。拆分后結構為:

  主啟動類 main.py

from app import app
import route

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8081, debug=True)

  app.py 包含 flask的app對象,和 SQLAlchemy的db對象

from flask import Flask
import configs
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
# 加載配置文件
app.config.from_object(configs)

db = SQLAlchemy(app)
# db綁定app
db.init_app(app)

  配置文件 configs.py

SECRET_KEY = "TEST_SECRET_KEY"

# sqlalchemy 的配置
SQLALCHEMY_DATABASE_URI = "mysql://root:123456@127.0.0.1:3306/db1"
# 如果設置成 True (默認情況),Flask-SQLAlchemy 將會追蹤對象的修改並且發送信號。這需要額外的內存, 如果不必要的可以禁用它。
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查詢時顯示原始SQL語句
SQLALCHEMY_ECHO = True

  路由 route.py

# coding:utf-8
from flask import Flask, render_template, redirect, url_for

from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

from app import db, app
from model.Author import Author
from model.Book import Book

# 定義表單模型類
class AuthorBookForm(FlaskForm):
    """自定義的表單模型類"""
    # DataRequired 驗證器:保證數據必填,並且不能為空
    author_name = StringField(label="作者", validators=[DataRequired("作者不能為空")])
    book_name = StringField(label="書籍", validators=[DataRequired("書籍不能為空")])
    submit = SubmitField(label="提交")


@app.route("/index", methods = ["get", "post"])
def index():
    # 創建表單對象。如果時post請求,前端發送了數據,flask會把數據在構造form對象的時候,存放到對象中
    authorBookForm = AuthorBookForm()

    author_li = Author.query.all()
    return render_template("author_book.html", authors=author_li, authorBookForm=authorBookForm)

@app.route("/add", methods = ["post"])
def add_book():
    # 創建表單對象。如果時post請求,前端發送了數據,flask會把數據在構造form對象的時候,存放到對象中
    authorBookForm = AuthorBookForm()

    # 判斷form中的數據是否合理。如果form中的數據完全滿足所有的驗證器,則返回真,否則返回假
    if authorBookForm.validate_on_submit():
        # 驗證通過
        author_name = authorBookForm.author_name.data
        book_name = authorBookForm.book_name.data
        print("驗證通過, author_name: {0}, book_name: {1}".format(author_name, book_name))

        # 根據作者名查詢, 保存書籍
        author = Author.query.filter_by(name=author_name).first()
        if author == None:
            auth = Author(name=author_name)
            db.session.add(auth)
            db.session.commit()

            book = Book(name=book_name, author_id = auth.id)
            db.session.add(book)
            db.session.commit()
        else:
            book = Book(name=book_name, author_id = author.id)
            db.session.add(book)
            db.session.commit()

    return redirect(url_for("index"))

@app.route("/delete_book/<book_id>")
def delete_book(book_id):
    print("delete_book book_id: {0}".format(book_id))
    if book_id == None:
        return redirect(url_for("index"))

    book = Book.query.get(book_id)
    if book == None:
        print("查詢不到書籍記錄, book_id: {0}".format(book_id))
    else:
        db.session.delete(book)
        db.session.commit()

    return redirect(url_for("index"))

@app.route("/delete_author/<author_id>")
def delete_author(author_id):
    print("delete_authro author_id: {0}".format(author_id))
    if author_id == None:
        return redirect(url_for("index"))

    author = Author.query.get(author_id)
    if author == None:
        print("查詢不到指定作者, author_id: {0}".format(author_id))
    else:
        # 先刪除作者下面所有書籍,然后刪除作者
        for book in author.books:
            db.session.delete(book)
        db.session.delete(author)
        db.session.commit()

    return redirect(url_for("index"))

  模型類 Author.py

from app import db

# 創建模型類
class Author(db.Model):
    __tablename__ = "tb_author"
    id = db.Column(db.Integer, primary_key = True) # 整形的主鍵,默認設置為自增主鍵
    name = db.Column(db.String(32), unique =True)
    
    books = db.relationship("Book", backref = "author")

  模型類 Book.py

from app import db

class Book(db.Model):
    __tablename__ = "tb_book"
    id = db.Column(db.Integer, primary_key = True) # 整形的主鍵,默認設置為自增主鍵
    name = db.Column(db.String(64), unique = True)
    author_id = db.Column(db.Integer, db.ForeignKey("tb_author.id")) # 外鍵,存儲tb_author表的id

 

2、循環依賴問題    <--返回目錄

  main.py

# coding:utf-8
from flask import Flask
from user import get_user # 這里發生循環依賴。main.py要導入user模塊,user模塊又要導入main.py

app = Flask(__name__)

if __name__ == "__main__":
    print(app.url_map) # 打印路由信息
    app.run(host="0.0.0.0", port=8081, debug=True)
from main import app

@app.route("/get_user")
def get_user():
    pass

  運行main.py報錯信息

ImportError: cannot import name 'get_user' from partially initialized module 'user' (most likely due to a circular import) (E:\pycode\user.py)

  

3、使用裝飾器解決路由模塊划分問題    <--返回目錄

  使用裝飾器解決路由模塊划分問題:app.route("/get_user")(get_user) 裝飾器就是一個函數,函數傳入的參數為裝飾器裝飾的函數名

  main.py

# coding:utf-8
from flask import Flask
from user import get_user # 這里發現循環依賴

app = Flask(__name__)
app.route("/get_user")(get_user)

if __name__ == "__main__":
    print(app.url_map) # 打印路由信息
    app.run(host="0.0.0.0", port=8081, debug=True)

  user.py

# from main import app

# @app.route("/get_user")
def get_user():
    pass

 

4、使用藍圖划分模塊    <--返回目錄

  BluePrint藍圖:用於實現單個應用的視圖、模板、靜態文件的集合。藍圖就是模塊處理的類。簡單來說,藍圖就是一個存儲操作路由映射方法的容器,主要用來實現客戶端請求和url相互關聯的功能。在Flask中,使用藍圖可以幫助我們實現模塊化應用的功能。

  藍圖的運行機制:藍圖是保存了一組將來可以在應用對象上執行的操作。注冊路由就是一種操作,當在程序實例上調用route裝飾器注冊路由時,這個操作將修改對象的url_map路由映射列表。當我們在藍圖對象上調用route裝飾器注冊路由時,它只是在內部的一個延遲操作記錄列表defered_functions中添加了一個項。當執行應用對象的register_blueprint()方法時,應用對象從藍圖對象的defered_functions列表中取出每一項,即調用應用對象的add_url_rule()方法,這將會修改程序實例的路由映射列表。

  藍圖的使用

from flask import Flask
from user import app_userss

app = Flask(__name__)
# 注冊藍圖
app.register_blueprint(app_userss)

if __name__ == "__main__":
    print(app.url_map) # 打印路由信息
    app.run(host="0.0.0.0", port=8081, debug=True)
from flask import Blueprint

# 創建一個藍圖對象,藍圖就是一個小模塊的抽象概念
app_userss = Blueprint("app_users", __name__)

@app_userss.route("/get_user")
def get_user():
    pass

 

  以目錄形式定義藍圖:在創建藍圖對象時 app_books = Blueprint("app_books", __name__, template_folder="templates")  中 __name__參數指定了這個藍圖對象尋找模板文件的起始點,template_folder="templates") 指定了模板目錄的名稱。

    main.py

# coding:utf-8
from flask import Flask
from book import app_books

app = Flask(__name__)
# 注冊藍圖
app.register_blueprint(app_books, url_prefix="/books")

if __name__ == "__main__":
    print(app.url_map) # 打印路由信息
    app.run(host="0.0.0.0", port=8081, debug=True)

  book目錄下面創建__init__.py,python就可以把book目錄當成一個模塊來使用。

  __init__.py

from flask import Blueprint

# 創建藍圖對象
app_books = Blueprint("app_books", __name__, template_folder="templates")

# 在 __init__.py文件被執行的時候,把視圖加載進來,讓藍圖和應用程序知道有視圖的存在
from .views import get_book

  views.py

from . import app_books
from flask import render_template

@app_books.route("/get_book")
def get_book():
    return render_template("book.html")

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM