Flask 來寫個輕博客 (33) — 使用 Flask-RESTful 來構建 RESTful API 之二

      網友投稿 860 2025-04-03

      Blog 項目源碼:https://github.com/JmilkFan/JmilkFan-s-Blog

      目錄

      目錄

      前文列表

      擴展閱讀

      構建 RESTful Flask API

      定義資源路由

      格式化輸出

      前文列表

      用 Flask 來寫個輕博客 (1) — 創建項目

      用 Flask 來寫個輕博客 (2) — Hello World!

      用 Flask 來寫個輕博客 (3) — (M)VC_連接 MySQL 和 SQLAlchemy

      用 Flask 來寫個輕博客 (4) — (M)VC_創建數據模型和表

      用 Flask 來寫個輕博客 (5) — (M)VC_SQLAlchemy 的 CRUD 詳解

      用 Flask 來寫個輕博客 (6) — (M)VC_models 的關系(one to many)

      用 Flask 來寫個輕博客 (7) — (M)VC_models 的關系(many to many)

      用 Flask 來寫個輕博客 (8) — (M)VC_Alembic 管理數據庫結構的升級和降級

      用 Flask 來寫個輕博客 (9) — M(V)C_Jinja 語法基礎快速概覽

      用 Flask 來寫個輕博客 (10) — M(V)C_Jinja 常用過濾器與 Flask 特殊變量及方法

      用 Flask 來寫個輕博客 (11) — M(V)C_創建視圖函數

      用 Flask 來寫個輕博客 (12) — M(V)C_編寫和繼承 Jinja 模板

      用 Flask 來寫個輕博客 (13) — M(V)C_WTForms 服務端表單檢驗

      用 Flask 來寫個輕博客 (14) — M(V)C_實現項目首頁的模板

      用 Flask 來寫個輕博客 (15) — M(V)C_實現博文頁面評論表單

      用 Flask 來寫個輕博客 (16) — MV(C)_Flask Blueprint 藍圖

      用 Flask 來寫個輕博客 (17) — MV(C)_應用藍圖來重構項目

      用 Flask 來寫個輕博客 (18) — 使用工廠模式來生成應用對象

      用 Flask 來寫個輕博客 (19) — 以 Bcrypt 密文存儲賬戶信息與實現用戶登陸表單

      用 Flask 來寫個輕博客 (20) — 實現注冊表單與應用 reCAPTCHA 來實現驗證碼

      用 Flask 來寫個輕博客 (21) — 結合 reCAPTCHA 驗證碼實現用戶注冊與登錄

      用 Flask 來寫個輕博客 (22) — 實現博客文章的添加和編輯頁面

      用 Flask 來寫個輕博客 (23) — 應用 OAuth 來實現 Facebook 第三方登錄

      用 Flask 來寫個輕博客 (24) — 使用 Flask-Login 來保護應用安全

      用 Flask 來寫個輕博客 (25) — 使用 Flask-Principal 實現角色權限功能

      用 Flask 來寫個輕博客 (26) — 使用 Flask-Celery-Helper 實現異步任務

      用 Flask 來寫個輕博客 (27) — 使用 Flask-Cache 實現網頁緩存加速

      用 Flask 來寫個輕博客 (29) — 使用 Flask-Admin 實現后臺管理 SQLAlchemy

      用 Flask 來寫個輕博客 (30) — 使用 Flask-Admin 增強文章管理功能

      用 Flask 來寫個輕博客 (31) — 使用 Flask-Admin 實現 FileSystem 管理

      用 Flask 來寫個輕博客 (32) — 使用 Flask-RESTful 來構建 RESTful API 之一

      擴展閱讀

      使用 Flask 設計 RESTful APIs

      快速入門 — Flask-RESTful 0.3.1 documentation

      Python爬蟲常用之HtmlParser

      構建 RESTful Flask API

      為什么要構建 RESTful API ?

      對于一個 blog application 而言, 其實完全可以不用到 restful api 也能滿足日常所需. 加入 restful api 的唯一目標就是加強該項目的可擴展性, 為后期所要實現的諸如: 博客遷移/數據備份/功能擴展 提供統一且可靠的接口.

      定義資源路由

      首先我們要有一個大概的需求, 如果希望通過 HTTP 請求來完成對服務端資源的操作, 我們需要解決那些問題?

      1. 首先要定位到該資源

      2. 告訴服務端我要對該資源做那種操作

      3. 前提還可能需要滿足身份鑒權(這個需求, 我們后期再實現)

      安裝 Flask-RESTful

      pip install Flask-Restful pip freeze > requirements.txt

      1

      2

      初始化 restful_api 對象

      vim jmilkfansblog/extensions.py

      from flask.ext.restful import Api ... #### Create the Flask-Restful's instance restful_api = Api()

      1

      2

      3

      4

      5

      實現 PostApi 資源類

      我們將 posts 博客文章定義為一類資源, 只有定義了資源并且對外公開后, 才能被外部所調用.

      vim jmilkfansblog/controllers/flask_restful/posts.py

      from flask.ext.restful import Resource class PostApi(Resource): """Restful API of posts resource.""" def get(self, post_id=None): """Can be execute when receive HTTP Method `GET`. Will be return the Dict object as post_fields. """ return {'hello': 'world'}

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      NOTE 1: jmilkfansblog/controllers/flask_restful 會作為一個包, 所以要記得創建 __init__.py 文件, 否則無法作為導入路徑.

      NOTE 2: 每個 REST 資源類都需要繼承 flask_restful 的 Resource 類. 其所有的子類都可以通過定義同名實例函數來將該函數綁定到 HTTP Methods 中. EG. GET <==> get(), 放接受定位到資源的 HTTP GET 方法時, 就會執行該資源類的實例函數 get() .

      將 restful_api 對象注冊到 app 對象中

      vim jmilkfansblog/__init__.py

      from jmilkfansblog.extensions import restful_api from jmilkfansblog.controllers.flask_restful.posts import PostApi ... def create_app(object_name): ... #### Init the Flask-Restful via app object # Define the route of restful_api restful_api.add_resource( PostApi, '/api/posts') restful_api.init_app(app)

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      NOTE 1: 在 restful_api.add_resource() 指定了資源類 PostApi 所對應的資源名稱為 posts, 訪問路由為 /api/posts, 這樣才完成了對一個資源的完整定義.

      NOTE 2: 同時再結合 PostApi 中的 get() 會自動的適配到 HTTP GET 方法, 這樣就解決了我們之前所提出的 2 個問題.

      現在我們引入一個新的問題, 通過上述定義的 get() 方法我們基本可以獲取到數據庫 posts 表中的所有記錄(當然現在還沒有連接數據庫操作), 那么如果我只需要獲取其中的某一條指定的記錄呢?

      這里需要在請求中指定 id 來完成單一的定位, 或者也可以傳遞一個 filters 來過濾若干條滿足要求的數據記錄.

      為資源 posts 添加多條路由

      vim jmilkfansblog/__init__.py

      def create_app(object_name): ... #### Init the Flask-Restful via app object # Define the route of restful_api restful_api.add_resource( PostApi, '/api/posts', '/api/posts/', endpoint='restful_api_post')

      1

      2

      3

      4

      5

      6

      用 Flask 來寫個輕博客 (33) — 使用 Flask-RESTful 來構建 RESTful API 之二

      7

      8

      9

      NOTE: add_resource() 允許為同一個資源類綁定多條路由, '/api/posts/' 表示可以訪問 posts 這一類資源中某一個 post_id 一致的資源對象.

      為 get() 方法添加 post_id 形參數

      vim jmilkfansblog/controllers/flask_restful/posts.py

      class PostApi(Resource): """Restful API of posts resource.""" def get(self, post_id=None): """Can be execute when receive HTTP Method `GET`. Will be return the Dict object as post_fields. """ if post_id: return {'post_id': post_id} return {'hello': 'world'}

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      格式化輸出

      在上一篇博文中提到, REST 約束要求我們使用一致的數據包裝形式來進行響應, 所以我們需要實現一致的格式化功能. 本項目使用最常見的 JSON 格式.

      Flask-Restful 的格式化輸出, 首先需要定義出一個類似模板的 Dict 類型對象

      其 keys 是資源對應的 Model 對象所擁有且需要輸出的字段名, values 則聲明了該字段的值以何種類型轉換并輸出. 然后把該字典模板傳給裝飾器 @marshal_with 并裝飾到所有資源類中需要返回數據到客戶端的實例方法中. 如此之后,實例方法在返回數據之前都會按照該模板將數據進行格式化轉換.

      注意: 字典模板的 keys 最好與 models 模塊中定義的字段名相同, 否則無法自動完成字典模板與 Model 對象的匹配.

      vim jmilkfansblog/controllers/flask_restful/posts.py

      from flask.ext.restful import Resource, fields, marshal_with from jmilkfansblog.controllers.flask_restful import fields as jf_fields ... # String format output of tag nested_tag_fields = { 'id': fields.String(), 'name': fields.String()} # String format output of post post_fields = { 'author': fields.String(attribute=lambda x: x.user.username), 'title': fields.String(), 'text': jf_fields.HTMLField(), 'tags': fields.List(fields.Nested(nested_tag_fields)), 'publish_date': fields.DateTime(dt_format='iso8601')} class PostApi(Resource): """Restful API of posts resource.""" @marshal_with(post_fields) def get(self, post_id=None): """Can be execute when receive HTTP Method `GET`. Will be return the Dict object as post_fields. """ if post_id: return {'post_id': post_id} return {'hello': 'world'}

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      NOTE 1: 這里需要使用到 flask_restful.fields, 其提供了絕大多數常用的格式類型定義, 具體格式類型列表可以查看官方文檔. 當然, 我們也可以自定義一些格式類型, 例如 jf_fields.HTMLField()

      NOTE 2: tags 和 author 字段并不存在與 posts 表中, 返回該字段是為了遵守 REST 的約束之一, RESTful API 返回的數據應該盡量滿足客戶端的需求. 所以我們一般會將表與表之前含有關聯關系的字段都一同返回. 格式類型 List 可以接受另外一個格式化輸出字典模板對象. 類似于 字典內嵌套字典的格式.

      自定義 fields 類型

      因為 posts 表中的 text 字段內容是一系列的 HTML 字符串(由 CKEditor 產生), 這些 HTML 字符串是不允許被 RESTful API 返回的, 因為要滿足 REST 的約束之一, 服務端不參與用戶界面表現層的業務邏輯(即 HTML 代碼), 所以我們需要將該字段值中的 HTML 標簽過濾掉.

      vim jmilkfansblog/controllers/flask_restful/fields.py

      from HTMLParser import HTMLParser from flask.ext.restful import fields class HTMLField(fields.Raw): """Define a new fields for filter the HTML tags string.""" def format(self, value): return strip_tags(str(value)) class HTMLStripper(HTMLParser): """HTML Parser of Stripper.""" def __init__(self): self.reset() self.fed = [] def handle_data(self, data_object): self.fed.append(data_object) def get_data(self): return ''.join(self.fed) def strip_tags(html): """Filter the tags string of HTML for data object of Restful api.""" stripper = HTMLStripper() stripper.feed(html) return stripper.get_data()

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      NOTE 1: 在 fields 模塊中通過繼承了 flask_restful.fields.Raw 類, 實現了新的格式類型 HTMLField .

      NOTE 2: 使用 HTTPParser 來實現 HTML 解析, 重載 handle_data 方法用于將 HTML 標簽之間的文本內容合并.

      API Flask

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel2003軟件安裝教程
      下一篇:將Excel中將表格轉換為圖片的方法(怎么把圖片中表格轉換成excel表格)
      相關文章
      亚洲一本之道高清乱码| 亚洲国产精品不卡在线电影| 67pao强力打造67194在线午夜亚洲 | 国产成人+综合亚洲+天堂| 亚洲欧美日韩中文字幕一区二区三区 | 亚洲男女性高爱潮网站| 亚洲AV美女一区二区三区| 在线观看亚洲精品国产| 精品亚洲一区二区三区在线观看| 久久亚洲AV成人无码国产电影| 精品亚洲成A人无码成A在线观看| 亚洲精品国产成人99久久| 怡红院亚洲怡红院首页| 亚洲成人高清在线| 日本亚洲欧美色视频在线播放| 亚洲精品乱码久久久久久V| 中文字幕乱码亚洲无线三区| 亚洲jjzzjjzz在线播放| 亚洲国产综合在线| 亚洲另类自拍丝袜第1页| 亚洲国产福利精品一区二区| 亚洲一区二区三区久久久久| 亚洲三级中文字幕| 77777亚洲午夜久久多喷| 亚洲中文精品久久久久久不卡| 亚洲综合一区国产精品| 亚洲av无码偷拍在线观看| 国产成人亚洲午夜电影| 久久精品国产精品亚洲| 狠狠色伊人亚洲综合成人| 亚洲AV区无码字幕中文色 | mm1313亚洲国产精品美女| 久久亚洲av无码精品浪潮| 亚洲av最新在线观看网址| 精品久久久久久亚洲中文字幕 | 亚洲国产精品国自产电影| 亚洲无线一二三四区| 亚洲av永久无码精品三区在线4 | 亚洲精品无码不卡在线播放| 亚洲A∨午夜成人片精品网站| 久久影视国产亚洲|