Flask-藍圖、模型與CodeFirst

来源:https://www.cnblogs.com/mengd/archive/2018/08/21/9514888.html
-Advertisement-
Play Games

應用、藍圖與視圖函數 1. 結構,如圖: 1. Flask最上層是 ,在這個核心對象上可以插入很多藍圖,這個藍圖是不能單獨存在的,必須將app作為插板插入app ,在每一個藍圖上,可以註冊很多靜態文件,視圖函數,模板 ,一個業務模塊可以做為一個藍圖,比如book,之前的book.py 放到了app/ ...


應用、藍圖與視圖函數

  1. 結構,如圖:

    藍圖

  2. Flask最上層是app核心對象 ,在這個核心對象上可以插入很多藍圖,這個藍圖是不能單獨存在的,必須將app作為插板插入app ,在每一個藍圖上,可以註冊很多靜態文件,視圖函數,模板 ,一個業務模塊可以做為一個藍圖,比如book,之前的book.py 放到了app/web/路徑下,就是考慮到了藍圖,app屬於是整個Flask應用層,web屬於是藍圖

  3. 一些初始化操作應該放入到__init__文件中,比如Flask的核心應用app初始化對象,應該放入到在應用層級app包的 __init__.py 中 ,而藍圖的初始化應該放入到藍圖層的web包__init__.py中,如圖:

    結構圖

  4. Flask的核心應用app初始化對象文件app/__init__.py

# -*- coding: utf-8 -*-
from flask import Flask

def create_app():
    app = Flask(__name__)
    app.config.from_object('config')
    # 要返回回去
    return app
  1. 此時在主文件中
# -*- coding: utf-8 -*-
from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run(debug=app.config['DEBUG'])

用藍圖註冊視圖函數

  1. 在藍圖中註冊試圖函數,在app/web/book.py中,記得導入Blueprint
# -*- coding: utf-8 -*-
from flask import jsonify, Blueprint
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook

# 藍圖 blueprint,進行初始化,藍圖的名字和參數為藍圖所在的模塊名一般用__name__
web = Blueprint ('web',__name__)

# 此時這裡用的就是web了
@web.route('/book/search/<q>/<page>')
def hello(q,page):
    is_or_key = is_isbn_key(q)
    if is_or_key == 'isbn':
        result = ShanqiuBook.search_by_isbn(q)
    else:
        result = ShanqiuBook.search_by_keyword(q)

    return jsonify(result)
  1. 在藍圖中註冊了試圖函數,還需要把藍圖插入到app中,app/__init__.py
# -*- coding: utf-8 -*-
from flask import Flask

def create_app():
    app = Flask(__name__)
    app.config.from_object('config')
    # 調用一下就可以
    register_blueprint(app)
    return app

# 通過這個方法插入到app中
def register_blueprint(app):
    from app.web.book import web
    # 註冊這個藍圖對象
    app.register_blueprint(web)

單藍圖多模塊拆分視圖函數

  1. 藍圖,就是為了分模塊的,比如一個web系統就是屬於一個web模塊,一個移動端使用的api就是一個api模塊,而我們這裡的book,user等不同類別的py文件,要是每一個都註冊一個藍圖的話就有點小題大作了,所以要進行單藍圖
  2. 在一個模塊(web)的初始文件中定義藍圖對象,然後這個模塊中的其他的py文件引用的就是這一個藍圖對象來註冊路由函數,
  3. 在app/web/book.py文件中
# -*- coding: utf-8 -*-
from flask import jsonify, Blueprint
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook
# 導入web模塊
from . import web

@web.route('/book/search/<q>/<page>')
def hello(q,page):

    # 調用方法判斷用戶是根據什麼查的
    is_or_key = is_isbn_key(q)
    if is_or_key == 'isbn':
        result = ShanqiuBook.search_by_isbn(q)
    else:
        result = ShanqiuBook.search_by_keyword(q)

    return jsonify(result)
  1. 這裡先建立一個偽代碼user.py,為了多一個模塊進行演示
# -*- coding: utf-8 -*-
# 導入web模塊
from . import web
@web.route("/user/login")
def login():
    return "success"
  1. 此時在app/web/__init__.py文件中,定義這個藍圖對象
# -*- coding: utf-8 -*-

# 藍圖 blueprint,進行初始化
from flask import Blueprint
web = Blueprint ('web',__name__)

# 這兩個導入之後就可以成功的運行對應模塊中相關的代碼,註意這個位置,這藍圖實例化之後
from app.web import book
from app.web import user

Request對象

  1. 在app/web/book.py文件中,定義的url請求是/book/search/<q>/<page>這種格式的,Flask會將<>里的值自動映射成視圖函數方法的參數,但是這種格式用著不爽,要把用戶輸入的參數作為請求參數傳入,這個時候就要使用這種格式了http://127.0.0.1:5000/book/search/?q=金庸&page=1
  2. 這個該怎麼獲取值呢,這個時候就用到Flask內置的Request了,通過request對象就可以獲取HTTP請求中包含的詳細信息了,具體的用法看下麵的代碼
# -*- coding: utf-8 -*-

# 導入這個request模塊,
from flask import jsonify, Blueprint,request
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook
from . import web

# http://127.0.0.1:5000/book/search/?q=金庸&page=1
@web.route('/book/search/')
def hello():
    # 通過Request對象拿到對應值的信息,但是這個並不是py中原始的字典,而是dict的子類immutableDict
    q = request.args['q']
    page = request.args['page']
    # ip = request.remote_addr

    # 通過這個方法把它轉換為普通的dict
    # a = request.args.to_dict()
    # print(a)

    is_or_key = is_isbn_key(q)
    if is_or_key == 'isbn':
        result = ShanqiuBook.search_by_isbn(q)
    else:
        result = ShanqiuBook.search_by_keyword(q)

    return jsonify(result)
  1. Flask的request是基於代理模式實現的,想讓request正常使用,必須確保是http請求觸發的函數或視圖函數中使用

WTForms參數驗證

  1. 上面我們把url改了,但是如果用戶輸入了一些特殊的符號該怎麼辦?這個時候就要使用到參數驗證,而WTForms框架就是一個優秀的參數驗證框架,首先在對應的環境中進行安裝(flask--yQglGu4) E:\py\qiyue\flask>pipenv install wtforms
  2. 這個參數驗證寫在哪裡好呢,直接寫在book.py中,這樣是最不妥的,為了方便調用,應該寫成一個類,所以寫在app/forms/book.py文件中
# -*- coding: utf-8 -*-

# 導入需要使用的模塊
from wtforms import Form,StringField,IntegerField
from wtforms.validators import Length,NumberRange

class SearchForm(Form):
    # 直接調用內置對象
    # 參數校驗規則:
    # 1.定義的屬性名q,page要與要校驗的參數同名
    # 2.根據要傳入的參數類型選擇不同的Field類進行實例化
    # 3.傳入一個數組,作為校驗規則validators
    # 4.可以設置預設值
    q = StringField(validators=[DataRequired(),Length(min=1,max=30)])

    page = IntegerField(validators=[NumberRange(min=1,max=10)],default=1)
  1. 此時在app/web/book.py文件中就可以直接調用就行了
# -*- coding: utf-8 -*-
from flask import jsonify, Blueprint,request
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook
from . import web
# 導入參數校驗
from app.forms.book import SearchForm

# http://127.0.0.1:5000/book/search/?q=金庸&page=1
@web.route('/book/search/')
def hello():

    # 驗證層
    # 實例化我們自定義的SearchForm,需要傳入一個字典作為要校驗的參數
    form  = SearchForm(request.args)
    # validate()方法返回True/False來標示是否校驗通過
    if form.validate():

        # 從form中取出校驗後的q與page,並且清除空格
        q = form.q.data.strip()
        page = form.page.data

        is_or_key = is_isbn_key(q)
        if is_or_key == 'isbn':
            result = ShanqiuBook.search_by_isbn(q)
        else:
            result = ShanqiuBook.search_by_keyword(q)
        return jsonify(result)
    else:
        return jsonify({'msg':'參數校驗失敗'})

拆分配置文件

  1. 之前訪問數據的時候,count和start都是寫死的,現在來進行重構,之前的代碼
   @classmethod
    def search_by_key(cls, q, count=15, start=0):
        # count:每頁顯示的數量
        # start:每頁的第一條數據的下標
        url = cls.search_by_key_url.format(q, count, start)
        return HTTP.get(url)
  1. 這樣寫非常的不妥

    • 在視圖函數中接收到的參數是page,代碼的封裝性,我們應該把count和start的計算過程放到ShanqiuBook.py的 search_by_key方法中來寫

    • count的值為了方便日後的管理,這個應該放入到配置文件中,之前的配置文件是config.py,在根目錄下,而這個應該放入到app目錄下,而關於一些比較隱私的配置信息要妥善處理,所以在app目錄下建立兩個文件,secure.py用來存放私密的配置信息,setting.py用於存放一些不重要的配置信息,如下

    • app/secure.py

      # -*- coding: utf-8 -*-
      
      # 存放比較機密的配置文件,在上傳git的時候不應該上傳此文件
      DEBUG = True
    • app/setting.py

      # -*- coding: utf-8 -*-
      
      # 生產環境和開發環境幾乎一樣的,不怎麼機密的配置文件
      
      # 每頁顯示的數據量
      PER_PAGE = 15
    • start的計算是一個單獨的邏輯,應該用封裝成一個方法,使用的時候直接調用

      # 獲取每一頁的起始下標
          @staticmethod
          def calculate_start(page):
              # 獲取配置信息中的每頁顯示的數量
              return (page -1 ) * current_app.config['PER_PAGE']
  2. 重構後的ShanqiuBook.py

   -*- coding: utf-8 -*-
   from httper import httper
# 通過這種方式來導入當前的app對象,方便調用配置而文件

   from flask import current_app

   class ShanqiuBook:

   isbn_url = 'http://t.yushu.im/v2/book/search/isbn/{}'
   keyword_url = 'http://t.yushu.im/v2/book/search?q={}&count={}&start={}'
   
   @classmethod
   def search_by_isbn(cls,isbn):
       url = cls.isbn_url.format(isbn)
       result = httper.get(url)
       return result
   
   @classmethod
   def search_by_keyword(cls,keyword,page=1):
       # 每頁顯示的數據(通過這種方式從配置文件中獲取到),每一頁的起始下標
       url = cls.keyword_url.format(keyword,current_app.config['PER_PAGE'],cls.calculate_start(page))
       result = httper.get(url)
       return result

# 獲取每一頁的起始下標
   @staticmethod
   def calculate_start(page):
       return (page -1 ) * current_app.config['PER_PAGE']​
  1. 這個時候在app/__init__.py文件中把配置文件添加到app中
#-- coding: utf-8 --

from flask import Flask

def create_app():

    app = Flask(name)

    # app.config.from_object('config')

    # 把配置文件裝載進來

    app.config.from_object('app.secure')

    app.config.from_object('app.setting')

    register_blueprint(app)

    return app

def register_blueprint(app):

    from app.web.book import web

    app.register_blueprint(web)

定義第一個模型類

  1. 我們現在把文件進行整理,如下:

目錄結構

  1. 首先在本地創建一個資料庫,如下:

新建資料庫

  1. 在app/models/book.py文件中建立模型,這裡使用到sqlalchemy來實現自動化映射,在Flask框架中對這個進行了改良Flask_SQLAlchemy,這個更加人性化,安裝(flask--yQglGu4) E:\py\qiyue\flask>pipenv install flask-sqlalchemy

  2. 建立模型,這樣就建立好了模型

# -*- coding: utf-8 -*-

# 首先導入
from sqlalchemy import Column,Integer,String

# sqlalchemy,自動化映射
# Flask_SQLAlchemy,這個是Flask封裝後的api,更加人性化

class Book():
    # 需要把這些屬性的預設值寫成sqlalchemy提供的固定的類型
    # Column()傳入參數:數據類型,主鍵,自增
    id = Column(Integer,primary_key=True,autoincrement=True)
    # 數據類型,不為空
    title = Column(String(50),nullable=False)
    author = Column(String(30),default='未名')
    binding = Column(String(20))
    publisher = Column(String(50))
    price = Column(String(20))
    pages = Column(Integer)
    pubdate = Column(String(20))
    # 唯一:unique=True
    isbn = Column(String(15),nullable=False,unique=True)
    summary = Column(String(1000))
    image = Column(String(50))
    
    # 定義一些方法
    def sample(self):
        pass


將模型映射到資料庫中

  1. 在模型類app/models/book.py中引入導入核心對象,並實例化,繼承
# -*- coding: utf-8 -*-
from sqlalchemy import Column,Integer,String

# 將模型映射到資料庫中
# 首先導入核心的對象
from flask_sqlalchemy import SQLAlchemy

# 初始化
db = SQLAlchemy()

# 繼承db.Model
class Book(db.Model):
    id = Column(Integer,primary_key=True,autoincrement=True)
    title = Column(String(50),nullable=False)
    author = Column(String(30),default='未名')
    binding = Column(String(20))
    publisher = Column(String(50))
    price = Column(String(20))
    pages = Column(Integer)
    pubdate = Column(String(20))
    isbn = Column(String(15),nullable=False,unique=True)
    summary = Column(String(1000))
    image = Column(String(50))

  1. app/__init__.py中進行模型與flask關聯
# -*- coding: utf-8 -*-
from flask import Flask
# 導入這個db
from app.models.book import db

def create_app():
    app = Flask(__name__)
    app.config.from_object('app.secure')
    app.config.from_object('app.setting')
    register_blueprint(app)


    # 把這個db和核心對象關聯起來了
    db.init_app(app)
    # 註意這裡,這樣寫的話會報錯
    db.create_all() # 把所有的數據模型映射到資料庫中
    return app

def register_blueprint(app):
    from app.web.book import web
    app.register_blueprint(web)
  1. 配置資料庫連接的配置文件在app/secure.py文件中
# -*- coding: utf-8 -*-

# 存放比較機密的配置文件
DEBUG = True

# 資料庫連接url,固定格式
# 要連接的資料庫類型,資料庫驅動(這裡還要進行安裝:pipenv install cymysql)
SQLALCHEMY_DATABASE_URI = 'mysql+cymysql://root:123456@localhost:3306/book'
  1. 之後運行項目,就會創建在指定的資料庫中創建一個數據表了,但是運行項目會出現下麵的這種錯誤
    'No application found. Either work inside a view function or push'
這個是因為在Flask中,不是實例化了app核心對象,其他代碼就可以直接使用,要在上面的第二步的註意事項中` db.create_all()`方法中,把app核心對象傳入即可

db.create_all(app=app),這樣就可以了,在資料庫中就可以看到表了

數據表結構


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 重載new,delete運算符 new,delete在c++中也被歸為運算符,所以可以重載它們。 new的行為: 先開闢記憶體空間 再調用類的構造函數 開闢記憶體空間的部分,可以被重載。 delete的行為: 先調用類的析構函數 再釋放記憶體空間 釋放記憶體空間的部分,可以被重載。 為什麼要要重載它們? 有 ...
  • Java 自學之路 前言 從運行第一個程式開始算起,我接觸編程也有三年的時間了。最初是從51單片機入門學習的C語言,班裡面的大佬帶著我一起做小項目,但是因為沒人教,基本靠自學,學得慢,寫的代碼也爛,很沒有章法。後來大三下半學期開始準備考研(從電子跨考電腦),從零開始學習數據結構,這才算是真正地入了 ...
  • 1、IOC&DI概述 IOC(Inversion of Control):其思想是反轉資源獲取的方向。傳統的資源查找方向要求組件向容器發起請求查找資源,作為回應,容器適時的返回資源。 而應用了IOC之後,則是容器主動地將資源推送給它所管理的組件,組件要做的僅是選擇一種合適方式來接受資源。也稱查找的被 ...
  • 《Spring Boot基礎教程》 第1節 工具的安裝和使用 Spring Boot文檔 https://qbgbook.gitbooks.io/spring-boot-reference-guide-zh/content/I.%20Spring%20Boot%20Documentation/ 一、 ...
  • 一.字元格式化輸出 占位符 %s s = string 字元串 %d d = digit 整數 %f f = float 浮點數 ''' ......'''不僅可以表示註釋多行,也可以表示列印多行。 二.str.isdigit()方法 檢查字元串是否只由數字組成 三.for迴圈 簡單的for迴圈,輸 ...
  • 一、前言 最近在做Matalb/Simulink與C/C++的混合編程,主要是完成TCP、UDP、SerialPort等常見通信方式的中間件設計,為Simulink模型提供數據採集及解析模塊。 問題在於沒有搞清楚Simulink中調用C/C++的內在機制,將測試OK的C++程式移植到mex上時,總會 ...
  • 楊輝三角有以下幾個特點 : 每個數等於它上方兩數之和。 每行數字左右對稱,由1開始逐漸變大。 第n行的數字有n項。 第n行數字和為2n-1。 第n行的m個數可表示為 C(n-1,m-1),即為從n-1個不同元素中取m-1個元素的組合數。 第n行的第m個數和第n-m+1個數相等 ,為組合數性質之一。 ...
  • 規則 1. 每次移動一個盤子 2. 任何時候大盤子在下麵,小盤子在上面 方法 假設共n個盤子 當n=1時: 1. 直接把A上的一個盤子移動到C上(A C) 當n=2時: 1. 把小盤子從A放到B上(A B) 這裡開始採用參數,rsc源地址=A,dst目的地址=B 2. 把大盤子從A放到C上( A C ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...