修剪原始數據,獲取真正需要的數據
在app
下新建一個view_modles
文件夾,用來存放view modle
,然後新建一個book.py
文件處理從yushu_book.py
中獲取的原始數據。因為在網頁中,需要獲取作者
,搜尋關鍵字
等信息,而從魚書api中獲取的信息有所不同,所以這個view modle
就是用來處理這些原始數據,把他轉化成我們需要的數據結構的模塊。
├── app
│ ├──forms
│ │ └── BookForm.py
│ ├── web
│ │ ├── __init_.py
│ │ ├── book.py
│ │ ├── setting.py
│ │ └── secure.py
│ ├──libs
│ │ ├── helper.py
│ │ └── HttpRequest.py
│ ├──view_modles
│ │ └── book.py
│ ├──spider
│ │ └── yushu_book.py
│ ├──models
│ │ └── sql_book.py
│ └── __init__.py
├── static
├── templates
├── fisher.py
# view_modle/book.py
class BookViewModle:
@classmethod
def package_single(cls,data,keyword):
returned = {
'books':[],
'total':0,
'keyword':keyword,
}
if data:
returned['total']= 1
returned['books']= [cls.__cut_book_data(data)]
return returned
@classmethod
def package_collection(cls,data,keyword):
returned = {
'books': [],
'total': 0,
'keyword': keyword,
}
if data:
returned['total'] = data['total']
returned['books'] = [cls.__cut_book_data(book) for book in data['books'] ]
# 運用列表推導式簡化代碼量
return returned
@classmethod
def __cut_book_data(cls,data):
book = {
'title':data['title'],
'publisher':data['publisher'],
'pages':data['pages'] or '', # 這裡當pages的值是null的時候返回空,有利於後期範本渲染
'price':data['price'] or '',
'author':'、'.join(data['author']), # 通過join方法快速拼接作者
'summary':data['summary'] or '',
'image':data['image'],
}
return book
然後在web/book.py
接收修剪後的數據。
# web/book.py
·····
from app.view_models.book import BookViewModle
·····
if isbn_or_key == 'isbn':
result = YuShuBook.search_by_isbn(q)
result = BookViewModle.package_single(result,q)
else:
result = YuShuBook.search_by_keyword(q,page)
result = BookViewModle.package_collection(result,q)
·····
然後就可以看到修剪後的數據效果了。
推倒前面的偽面向對象
發現面向對象中絕大多數都是code>@classmethod,如果面向對象中出現大量可以被作為code>@classmethod的方法,就可以說他是一個偽面向對象,不是用面向對象的思想構建的。例如yushu_book.py
下的YuShuBook
類,之所以出現這種問題是因為這個類自身並不會去儲存數據,而是把所有數據都返回給了調用方,只是包裝了一系列方法,去除了這個類名,他依然可以調用,所以應該把這些類的特徵儲存在這個類中,而不是返回給調用方。所以重構一下YuShuBook
類
#spider/yushu_book.py
from app.libs.HttpRequest import HTTP
from flask import current_app
class YuShuBook:
isbn_url = 'http://t.yushu.im/v2/book/isbn/{}'
keyword_url = 'http://t.yushu.im/v2/book/search?q={}&start={}&count={}'
def __init__(self):
self.total = 0
self.books = []
def search_by_isbn(self,isbn):
url = self.isbn_url.format(isbn)
# 如果中沒有這個屬性就會從類屬性中去找
result = HTTP.get(url)
self.__file_single(result)
def search_by_keyword(self,keyword,page=1):
url = self.keyword_url.format(keyword,self.get_start_page(page),current_app.config['PRE_PAGE'])
result = HTTP.get(url)
self.__file_conllection(result)
def __file_single(self,data):
if data:
self.total = 1
self.books.append(data)
def __file_conllection(self,data):
if data:
self.total = data['totak']
self.books = data['books']
def get_start_page(page):
return (page-1) * current_app.config['PRE_PAGE']
推倒整個BookViewModle
,重寫view_modles
下的book.py
# view_modles/book.py
class BookViewModle:
def __init__(self,book):
self.title = book['title']
self.title = book['title']
self.publisher= book['publisher']
self.pages= book['pages']
self.price = book['price']
self.author = '、'.join(book['author'])
self.summary = book['summary']
self.image= book['image']
class BookCollection:
def __init__(self):
self.total = 0
self.books =[]
self.keyword = ''
def fill(self, yushu_book, keyword):
self.total = yushu_book.total
self.keyword = keyword
self.books = [BookViewModle() for book in yushu_book.books]
重寫主視圖函式下的serach
視圖函式
#web/book.py
@web.route('/book/search')
·····
from app.view_models.book import BookViewModle
from app.view_models.book import BookCollection
·····
def search():
form = SearchForm(request.args)
books = BookCollection()
if form.validate():
q = form.q.data.strip()
page = form.page.data
isbn_or_key = is_isbn_or_key(q)
yushu_book = YuShuBook()
if isbn_or_key == 'isbn':
yushu_book.search_by_isbn(q)
else:
yushu_book.search_by_keyword(q,page)
books.fill(yushu_book,q)
return jsonify(books)
#注意這個時候在查詢是得不到數據的,因為這時候是一個對象實例,python不能把一個實例 序列化,因為之後的範本渲染不需要json所以這裡不需要繼續操作
else:
return jsonify(form.errors)
#這裡不採用自訂的錯誤了,直接返回表單驗證的錯誤信息
理解一下這個順序,首先把BookCollection
實例化,然後如果表單驗證通過,實例化YuShuBook
來接收數據,然後分別判斷isbn
和keyword
,進行調用類方法來獲取數據,並且儲存在yushu_book
這個對象中,最後調用books
這個對象的fill
方法,來修剪得到的數據,返回我們需要的數據並且存在books
這個對象中。整個過程還是挺抽象的。
如果你想返回一個json對象,那麼你可以這樣做
·····
import json
·····
return json.dumps(books,default=lambda o:o.__dict__)
#將return jsonify(books)替換