詳解Flask前后端分離項(xiàng)目案例
簡介
學(xué)習(xí)慕課課程,F(xiàn)lask前后端分離API后臺接口的實(shí)現(xiàn)demo,前端可以接入小程序,暫時(shí)已經(jīng)完成后臺API基礎(chǔ)架構(gòu),使用 postman 調(diào)試.git
重構(gòu)部分:
- ken校驗(yàn)?zāi)K
- auths認(rèn)證模塊
- scope權(quán)限模塊,增加全局掃描器(參考flask HTTPExceptions模塊)
收獲
- 我們可以接受定義時(shí)的復(fù)雜,但不能接受調(diào)用時(shí)的復(fù)雜
- 如果你覺得寫代碼厭倦,無聊,那你只是停留在功能的實(shí)現(xiàn)上,功能的實(shí)現(xiàn)很簡單,你要追求的是更好的寫法,抽象的藝術(shù),不是機(jī)械的勞動而是要 創(chuàng)造 ,要有自己的思考
- Sqlalchemy 中對類的創(chuàng)建都是用元類的方式,所以調(diào)用的時(shí)候都不用實(shí)例化,當(dāng)我們重寫 __init__ 方法是需要調(diào)用 orm.reconstrcut 裝飾器,才會執(zhí)行實(shí)例化對象的構(gòu)造函數(shù)
- 權(quán)限等級模塊的設(shè)計(jì)( api訪問權(quán)限 ),如超級管理員,管理員,普通用戶,訪客,這四者之間的關(guān)系,有包含的關(guān)系,所以可以考慮合并也可以考慮排除的方式來構(gòu)建權(quán)限控制模塊. 參考本項(xiàng)目中的 app.libs.scope
- 學(xué)的是解決問題的方法,首先要有深度,在去考慮廣度,還要懂得遷移應(yīng)用,形成自己的思維模型。
知識點(diǎn)復(fù)盤
初始化flask應(yīng)用程序
app = Flask(__name__, static_folder='views/statics', static_url_path='/static', template_folder="templates")
創(chuàng)建Flask應(yīng)用程序?qū)嵗龑ο? 如果模塊存在,會根據(jù)模塊所在的目錄去尋找靜態(tài)文件和模塊文件, 如果模塊不存在,會默認(rèn)使用app對象所在的項(xiàng)目目錄
- __name__ 表示以此模塊所在的目錄作為工作目錄,就是靜態(tài)文等從這個(gè)目錄下去找
- static_folder 指定靜態(tài)文件存放相對路徑 flask默認(rèn)會用/進(jìn)行分割然后取最后一個(gè)作為訪問 url 類似 Django 中的 STATICFILES_DIRS
- static_url_path 指定訪問靜態(tài)文件的 url 地址前綴, 類似 Django 中的 STATIC_URL
- template_folder 指定模板文件的目錄
@property def static_url_path(self): """The URL prefix that the static route will be accessible from. If it was not configured during init, it is derived from :attr:`static_folder`. """ if self._static_url_path is not None: return self._static_url_path if self.static_folder is not None: basename = os.path.basename(self.static_folder) return ("/" + basename).rstrip("/") @static_url_path.setter def static_url_path(self, value): if value is not None: value = value.rstrip("/") self._static_url_path = value
Flask 中 url 相關(guān)底層類
- BaseConverter 子類:保存提取 url 參數(shù)匹配規(guī)則
- Rule 類:記錄一個(gè) url 和一個(gè)視圖函數(shù)的對應(yīng)關(guān)系
- Map 類:記錄所有 url 地址和試圖函數(shù)對應(yīng)的關(guān)系 Map(Rule, Rule, ....)
- MapAdapter 類:執(zhí)行 url 匹配的過程,其中有一個(gè) match 方法, Rule.match(path, method)
自定義路由管理器
from flask import Flask app = Flask(__name__) from werkzeug.routing import BaseConverter class RegexUrl(BaseConverter): # 指定匹配參數(shù)時(shí)的正則表達(dá)式 # 如: # regex = '\d{6}' def __init__(self, url_map, regex): """ :param url_map: flask會自動傳遞該參數(shù) :param regex: 自定義的匹配規(guī)則 """ super(RegexUrl, self).__init__(url_map) self.regex = regex # 在對應(yīng)的試圖函數(shù)之前調(diào)用 # 從url中提取出參數(shù)之后,會先調(diào)用to_python # 會把提取出的值作為參數(shù)傳遞給to_pthon在返回給對應(yīng)的試圖 def to_python(self, value): """可以在這里做一些參數(shù)的類型轉(zhuǎn)換""" return value # 調(diào)用url_for時(shí)會被調(diào)用, 用來處理url反向解析時(shí)url參數(shù)處理 # 返回值用來拼接url def to_url(self, value): """對接收到參數(shù)做一些過濾等""" return value # 將自定義路由轉(zhuǎn)換器類添加到轉(zhuǎn)換器字典中 app.url_map.converters['re'] = RegexUrl # 案例 @app.route('/user/<re("[a-z]{3}"):id>') def hello(id): return f'hello {id}' if __name__ == '__main__': app.run(debug=True)
全局異常捕獲
AOP編程思想,面向切面編程,把事件統(tǒng)一在一個(gè)地方處理,在一個(gè)統(tǒng)一的出口做處理
errorhandler 在flask 1.0版本之前只支持填寫對應(yīng)的錯誤碼,比如 @app.errorhandler(404)
在flask1.0版本之后就支持全局的異常捕獲了 @app.errorhandler(code_or_exception) ,有了這個(gè)之后,就可以在全局做一個(gè)異常捕獲了,不用每個(gè)視圖函數(shù)都做異常捕獲。
@app.errorhandler(Exception) def framework_error(e): if isinstance(e, APIException): return e elif isinstance(e, HTTPException): code = e.code msg = e.description error_code = 1007 return APIException(msg, code, error_code) else: if not current_app.config['DEBUG']: return ServerError() else: raise e
異常類型
- 可預(yù)知的異常(已知異常)
- 完全沒有意識的異常(未知異常)
- abort函數(shù)
- abort(狀態(tài)碼) 是一個(gè)默認(rèn)的拋出異常的方法
- 調(diào)用abort函數(shù)可以拋出一個(gè)指定狀態(tài)碼對應(yīng)的異常信息
- abort函數(shù)會立即終止當(dāng)前視圖函數(shù)的運(yùn)行**
模型對象的序列化
場景:我們有時(shí)候可能需要返回模型對象中的某些字段,或者全部字段,平時(shí)的做法就是將對象中的各個(gè)字段轉(zhuǎn)為字典在返回 jsonnify(data) , 但是這樣的寫法可能在每個(gè)需要返回?cái)?shù)據(jù)的試圖函數(shù)中都寫一個(gè)對應(yīng)的字典。。對象轉(zhuǎn)字典在返回。 json 默認(rèn)是不能序列化對象的,一般我們的做法是 json.dumps(obj, default=lambda o: o.__dict__) 但是 __dict__ 中只保存實(shí)例屬性,我們的模型類基本定義的類屬性。解決這個(gè)問題就要看 jsonify 中是如何做序列化的,然后怎么重寫。
重寫 JSONEncoder
from datetime import date from flask import Flask as _Flask from flask.json import JSONEncoder as _JSONEncoder class JSONEncoder(_JSONEncoder): """ 重寫json序列化,使得模型類的可序列化 """ def default(self, o): if hasattr(o, 'keys') and hasattr(o, '__getitem__'): return dict(o) if isinstance(o, date): return o.strftime('%Y-%m-%d') super(JSONEncoder, self).default(o) # 需要將重寫的類綁定到應(yīng)用程序中 class Flask(_Flask): json_encoder = JSONEncoder
模型類的定義
class User(Base): id = Column(Integer, primary_key=True) email = Column(String(24), unique=True, nullable=False) nickname = Column(String(24), unique=True) auth = Column(SmallInteger, default=1) _password = Column('password', String(100)) def keys(self): return ['id', 'email', 'nickname', 'auth'] def __getitem__(self, item): return getattr(self, item)
注意: 修改了 json_encode 方法后,只要調(diào)用到 flask.json 模塊的都會走這個(gè)方法
為什么要寫 keys 和 __getitem__ 方法
當(dāng)我們使用 dict(object) 操作一個(gè)對象的時(shí)候, dict 首先會到實(shí)例中找 keys 的方法,將其返回列表的值作為 key , 然后會根據(jù) object[key] 獲取對應(yīng)的值,所以實(shí)例要實(shí)現(xiàn) __getitem__ 方法才可以使用中括號的方式調(diào)用屬性
進(jìn)階寫法- 控制返回的字段
場景:當(dāng)我們有一個(gè) Book 的模型類,我們的 api 接口可能需要返回 book 的詳情頁所以就要返回所有字典,但另外一個(gè)接口可能只需要返回某幾個(gè)字段。
class Book(Base): 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)) # orm實(shí)例化對象, 字段需要寫在構(gòu)造函數(shù)中,這樣每個(gè)實(shí)例對象都會有自己的一份,刪除增加都不會互相影響 @orm.reconstructor def __init__(self): self.fields = ['id', 'title', 'author', 'binding', 'publisher', 'price', 'pages', 'pubdate', 'isbn', 'summary', 'image'] def keys(self): return self.fields if hasattr(self, 'fields') else [] def hide(self, *keys): for key in keys: self.fields.remove(key) return self def append(self, *keys): for key in keys: self.fields.append(key) return self @api.route('/search') def search(): books = Book.query.filter().all() # 根據(jù)某些條件搜索的 books = [book.hide('summary') for book in books] return jsonify(books) @api,route('/<isbn>/detail') def detail(isbn): book = Book.query.filter_by(isbn=isbn).first_or_404() return jsonify(book)
請求鉤子函數(shù)
- before_first_request:在處理第一個(gè)請求前運(yùn)行。
- before_request:在每次請求前運(yùn)行。
- after_request:如果沒有未處理的異常拋出,在每次請求后運(yùn)行。
- teardown_request:在每次請求后運(yùn)行,即使有未處理的異常拋出。
全局掃描器
模仿flask exceptions 預(yù)加載各個(gè)異常類的方式,將用戶組自動加載進(jìn)內(nèi)存中,這樣獲取的話就更方便
str2obj = {} level2str = {} def iteritems(d, *args, **kwargs): return iter(d.items(*args, **kwargs)) def _find_scope_group(): for _name, obj in iteritems(globals()): try: is_scope_obj = issubclass(obj, BaseScope) except TypeError: is_scope_obj = False if not is_scope_obj or obj.level < 1: continue old_obj = str2obj.get(_name, None) if old_obj is not None and issubclass(obj, old_obj): continue str2obj[_name] = obj level2str[obj.level] = _name # 模仿flask exceptions 預(yù)加載各個(gè)異常類的方式,將用戶組自動加載進(jìn)內(nèi)存 _find_scope_group() del _find_scope_group
常見bug
form 正則校驗(yàn)注意事項(xiàng)
r'{6, 25}$'
帶空格和不帶空格是兩碼事, 正則里面{,} 連續(xù)不帶空格
r'{6,25}$'
參考
Python Flask高級編程之RESTFul API前后端分離精講
到此這篇關(guān)于詳解Flask前后端分離項(xiàng)目案例的文章就介紹到這了,更多相關(guān)Flask前后端分離 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解python使用Nginx和uWSGI來運(yùn)行Python應(yīng)用
這篇文章主要介紹了詳解python使用Nginx和uWSGI來運(yùn)行Python應(yīng)用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01flask中響應(yīng)錯誤的處理及errorhandler的應(yīng)用方式
這篇文章主要介紹了flask中響應(yīng)錯誤的處理及errorhandler的應(yīng)用方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12Python利用BeautifulSoup解析Html的方法示例
BeautifulSoup是python的一個(gè)庫,最主要的功能是從網(wǎng)頁抓取數(shù)據(jù)。下面這篇文章主要給大家介紹了關(guān)于Python利用BeautifulSoup解析Html的方法示例,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面跟著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2017-07-07Python使用pptx實(shí)現(xiàn)復(fù)制頁面到其他PPT中
這篇文章主要為大家詳細(xì)介紹了python如何使用pptx庫實(shí)現(xiàn)從一個(gè)ppt復(fù)制頁面到另一個(gè)ppt里面,文中的示例代碼講解詳細(xì),感興趣的可以嘗試一下2023-02-02我在七夕佳節(jié)用Python制作的表白神器,程序員也應(yīng)該擁有愛情!建議收藏
這篇文章主要介紹了我在七夕佳節(jié)用Python制作的表白神器,建議收藏,程序員也該擁有愛情,感興趣的小伙伴快來看看吧2021-08-08Python使用lambda拋出異常實(shí)現(xiàn)方法解析
這篇文章主要介紹了Python使用lambda拋出異常實(shí)現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08python圖片和二進(jìn)制轉(zhuǎn)換的三種實(shí)現(xiàn)方式
本文介紹了將PIL格式、數(shù)組和圖片轉(zhuǎn)換為二進(jìn)制的不同方法,包括使用PIL庫、OpenCV和直接讀取二進(jìn)制,此外,還提到了數(shù)據(jù)傳輸中base64格式的應(yīng)用,這些信息對需要進(jìn)行圖片數(shù)據(jù)處理和轉(zhuǎn)換的開發(fā)者非常有用2024-09-09Python中使用socks5設(shè)置全局代理的方法示例
這篇文章主要介紹了Python中使用socks5設(shè)置全局代理的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04Pycharm保存不能自動同步到遠(yuǎn)程服務(wù)器的解決方法
今天小編就為大家分享一篇Pycharm保存不能自動同步到遠(yuǎn)程服務(wù)器的解決方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06Python機(jī)器學(xué)習(xí)NLP自然語言處理基本操作之京東評論分類
自然語言處理( Natural Language Processing, NLP)是計(jì)算機(jī)科學(xué)領(lǐng)域與人工智能領(lǐng)域中的一個(gè)重要方向。它研究能實(shí)現(xiàn)人與計(jì)算機(jī)之間用自然語言進(jìn)行有效通信的各種理論和方法2021-10-10