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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...