Flask-數據與路由

數據

圖書數據庫的地址python

# 基地址
http://t.yushu.im
# 關鍵字搜索
http://t.yushu.im/v2/book/search?q={}&start={}&count={}
# isbn搜索
http://t.yushu.im/v2/book/search/isbn/{isbn}
# 豆瓣api
https://api.douban.com/v2/book/1003078

搜索關鍵字

  1. 根據上面的地址能夠知道搜索的時候有兩種方式,而對於isbn搜索,又分爲兩種isbn13 由13個0-9在數字組成,isbn10 由10表0-9表數字組組成,中間可能包含' - ' ,因此要分開來判斷
  2. 在函數中要注意:isdigit()能夠判斷是否爲數字 ,replace()用來替換,
@app.route("/search/<q>/<page>")
def search(q,page):
    """
    搜索書籍路由
    :param q: 關鍵字 OR isbn
    :param page: 頁碼
    """
    isbn_or_key = 'key'
    # 1. 判斷長度是否爲13且是否爲數字
    if len(q) == 13 and q.isdigit():
        isbn_or_key = 'isbn'
    # 2. 把-替換掉,判斷是否爲純數字
    short_q = q.replace('-', '')
    if '-' in q and len(short_q) == 10 and short_q.isdigit():
        isbn_or_key = 'isbn'
    pass
  1. 多邏輯判斷的時候,應該把結果看着爲假的放到前面,對數據庫操做的放到後面,這樣有利於節約資源

簡單的重構

  1. 上面的代碼都寫到視圖中這樣不妥,體現不了封裝性,看起來很差,應該把一個實現的功能封裝起來,創建一個函數,方便往後的管理
  2. 在目錄下創建一個helper.py文件,這個文件主要就是提供一些方法,把上面的內容放到這裏,只須要返回一個值就能夠了
# -*- coding: utf-8 -*-

def is_isbn_or_key(word):
    isbn_or_key = 'key'
    if len(word) == 13 and word.isdigit():
        isbn_or_key = 'isbn'

    short_word = word.replace('-', '')
    if '-' in word and len(short_word) == 10 and short_word.isdigit():
        isbn_or_key = 'isbn'

    return isbn_or_key
  1. 在主文件中調用這個方法就能夠了,記得傳值,和接收返回的值
# -*- coding: utf-8 -*-

from flask import Flask,make_response
# 1. 這裏要導入
from helper import is_isbn_or_key

app = Flask(__name__)
app.config.from_object('config')

@app.route('/book/search/<q>/<page>')
def search(q,page):
    # 2. 調用方法便可
    is_or_key = is_isbn_or_key(q)
    pass

if __name__ == '__main__':
    app.rundebug=app.config['DEBUG'])

requests請求

  1. 由於這個項目要訪問不一樣的網址,因此在目錄下新建一個http.py文件,專門用來提供訪問網址
  2. 這裏使用的requests,要先進行安裝,注意:代碼寫的時候必定要簡潔,千萬不要使用python的關鍵字,以避免與Python的模塊衝突並致使此錯誤,把這個類名http改成別的名稱
# -*- coding: utf-8 -*-

import requests
class aaa:

    # 傳入url和是否返回的是json數據,這裏是靜態方法
    @staticmethod
    def get(url,return_json=True):
        # 發送get請求
        r = requests.get(url)
        # 由於有的url返回的json數據,可是有的並非,因此加一個判斷,不是的話返回文本
        # 還要判斷狀態碼,200的話就是訪問成功有數據
        if r.status_code != 200:
            return {} if return_json else ''
        return r.json() if return_json else r.text

        # 下面的寫法太low
        # if r.status_code == 200:
        #     if return_json:
        #         return r.json()
        #     else:
        #         return r.text
        # else:
        #     if return_json:
        #         return {}
        #     else:
        #         return ''

從API中獲取數據

  1. 首先在目錄下定義一個類,用於用於獲取數據,ShanqiuBook,
# -*- coding: utf-8 -*-

from http import aaa
class ShanqiuBook:

    isbn_url = 'http://t.yushu.im/v2/book/search/isbn/{}'
    keyword_url = 'http://t.yushu.im/v2/book/search?q={}&count={}&start={}'


    # 根據isbn進行搜索,這裏使用這個靜態裝飾器,調用類變量更加的方便
    @classmethod
    def search_by_isbn(cls,isbn):
        # 調用類變量,
        url = cls.isbn_url.format(isbn)
        # 調用上面的方法用於請求網址
        result = aaa.get(url)
        # 這裏返回的是json數據,可是在py中就是字典了
        return result

    # 根據關鍵字進行搜索
    @classmethod
    def search_by_keyword(cls,keyword,count=15,start=0):
        url = cls.keyword_url.format(keyword,count,start)
        result = aaa.get(url)
        return result
  1. 而後在視圖中獲取返回的數據
# -*- coding: utf-8 -*-

from flask import Flask
from helper import is_isbn_or_key

from flask import jsonify
# 實例化
from shanqiu_book import ShanQiuBook

app = Flask(__name__)
# 載入這個配置文件
app.config.from_object('config')

@app.route('/book/search/<q>/<page>')
def search(q,page):
     is_or_key = is_isbn_or_key(q)
     if is_or_key == 'isbn':
         # 這裏直接使用使用類名調用就能夠
         result = ShanQiuBook.search_by_isbn(q)
    else:
         result = ShanQiuBook.search_by_keyword(q)
    
    # 由於返回的是json數據,要手動的進行解析,這樣寫的話很是麻煩
    # return json.dumps(result), 200, {'content-type': 'application/json'}
    # 這裏使用flask自帶的jsonify替換麻煩的json.dumps和元組
     return jsonify(result)

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

將視圖函數拆分到單獨的文件中

  1. 若是視圖函數都寫在主文件中,不利於維護,而是應該把他們放入到一個文件中,每個模塊就是一個試圖,用的時候直接引用,這樣有利於維護
  2. 在根目錄下創建一個app/web文件夾,在這個文件夾下面創建一個book.py文件,專門用來存放book模塊,而後在主文件中引用這個模塊就能夠了,book.py
# -*- coding: utf-8 -*-
from flask import jsonify
from helper import is_isbn_key
from ShanqiuBook import ShanqiuBook

# 爲了讓book.py模塊可使用app對象
from demo import app

@app.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. 此時的主文件中
# -*- coding: utf-8 -*-
from flask import Flask
# 爲了能夠註冊book.py中的路由
from app.web import book

app = Flask(__name__)
app.config.from_object('config')

if __name__ == '__main__':
    app.run(debug=app.config['DEBUG'])
  1. 可是這樣寫的話,會出現404,由於出現了循環引用

循環引入流程分析

  1. 由於在整個的流程中,app兩次初始化,如圖
  2. 解釋
  3. 整個流程中,出現了兩次核心app對象的初始化,註冊路由是在藍色流程中初始化的app註冊的。可是啓動服務是紅色流程中的app啓動的
  4. book中註冊路由所使用的app對象,是他本身所導入fisher模塊的app對象(藍色流程中),而不是紅色主流程中所實例化的app對象
  5. 問題1:由於都是由fisher引入book,一個模塊只會引入另外一個模塊一次,因此只執行了一次book
  6. 問題2:因爲一次是主流程執行fisher文件;一次是由book模塊導入 fisher
  7. 爲了驗證咱們的結論,咱們在app實例化,啓動,註冊路由是哪一個地方加入日誌信息,
print("id爲"+str(id(app))+"的app註冊路由")
@app.route("/book/search/<q>/<page>")
def search(q, page):
    isbn_or_key = is_isbn_or_key(q)
    if isbn_or_key == 'isbn':
        result = YuShuBook.search_by_isbn(q)
    else:
        result = YuShuBook.search_by_key(q)
    return jsonify(result)
  1. 主文件
app = Flask(__name__)
print("id爲"+str(id(app))+"的app實例化")
app.config.from_object("config")
# 爲了能夠註冊book.py中的路由
from app.web import book
if __name__ == '__main__':
    print("id爲" + str(id(app)) + "的app啓動")
    app.run(debug=app.config['DEBUG'])
  1. 結果以下
id爲92323280的app實例化
id爲107142192的app實例化
id爲107142192的app註冊路由
id爲92323280的app啓動

能夠看到註冊路由的app,和啓動服務的app不是同一個app。而且最後啓動的app是最早實例化的app,也就是紅色主流程的app;而註冊路由的app是後實例化的app,也就是由book導入fisher模塊的藍色流程的appgit

相關文章
相關標籤/搜索