Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog

目录

前文列表

用 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
  • 初始化 restful_api 对象

    vim jmilkfansblog/extensions.py
from flask.ext.restful import Api
... #### Create the Flask-Restful's instance
restful_api = Api()
  • 实现 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'}

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)

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/<string:post_id>',
endpoint='restful_api_post')

NOTE: add_resource() 允许为同一个资源类绑定多条路由, '/api/posts/<string:post_id>' 表示可以访问 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'}

格式化输出

在上一篇博文中提到, 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'}

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()

NOTE 1: 在 fields 模块中通过继承了 flask_restful.fields.Raw 类, 实现了新的格式类型 HTMLField .

NOTE 2: 使用 HTTPParser 来实现 HTML 解析, 重载 handle_data 方法用于将 HTML 标签之间的文本内容合并.

用 Flask 来写个轻博客 (33) — 使用 Flask-RESTful 来构建 RESTful API 之二的更多相关文章

  1. 用 Flask 来写个轻博客

    用 Flask 来写个轻博客 用 Flask 来写个轻博客 (1) — 创建项目 用 Flask 来写个轻博客 (2) — Hello World! 用 Flask 来写个轻博客 (3) — (M)V ...

  2. 用 Flask 来写个轻博客 (37) — 在 Github 上为第一阶段的版本打 Tag

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 第一阶段结语 打 Tag 前文列表 用 Flask 来写个轻博客 (1 ...

  3. 用 Flask 来写个轻博客 (36) — 使用 Flask-RESTful 来构建 RESTful API 之五

    目录 目录 前文列表 PUT 请求 DELETE 请求 测试 对一条已经存在的 posts 记录进行 update 操作 删除一条记录 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 ...

  4. 用 Flask 来写个轻博客 (35) — 使用 Flask-RESTful 来构建 RESTful API 之四

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 POST 请求 身份认证 测试 前文列表 用 Flask 来写个轻博客 ...

  5. 用 Flask 来写个轻博客 (34) — 使用 Flask-RESTful 来构建 RESTful API 之三

    目录 目录 前文列表 应用请求中的参数实现 API 分页 测试 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写个轻博客 (2) - Hello World! 用 F ...

  6. 用 Flask 来写个轻博客 (32) — 使用 Flask-RESTful 来构建 RESTful API 之一

    目录 目录 前文列表 扩展阅读 RESTful API REST 原则 无状态原则 面向资源 RESTful API 的优势 REST 约束 前文列表 用 Flask 来写个轻博客 (1) - 创建项 ...

  7. 用 Flask 来写个轻博客 (31) — 使用 Flask-Admin 实现 FileSystem 管理

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 编写 FileSystem Admin 页面 Flask-A ...

  8. 用 Flask 来写个轻博客 (30) — 使用 Flask-Admin 增强文章管理功能

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 实现文章管理功能 实现效果 前文列表 用 Flask 来写个 ...

  9. 用 Flask 来写个轻博客 (29) — 使用 Flask-Admin 实现后台管理 SQLAlchemy

    目录 目录 前文列表 扩展阅读 Flask-Admin BaseView 基础管理页面 ModelView 实现效果 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写 ...

随机推荐

  1. openssl使用

    一. 加密方法 dsaffdfd fgggg 1.对称加密: 加密算法 + 口令 加密算法: DES(56bits),3DES(用des加密反复加密三次),AES(128bits),Blowfish ...

  2. mac下使用iterm实现自动登陆

    1.通过brew安装sshpass(手动安装也可以) ①brew安装sshpass brew install https://raw.githubusercontent.com/kadwanev/bi ...

  3. Numpy的基础使用

    数据分析: 是把隐藏在一些看似杂乱无章的数据背后的信息提取出来,总结出所研究对象的内在规律 数据分析的三剑客: Numpy, Pandas, Matplotlib NumPy(Numerical Py ...

  4. MVC路由学习:自定义路由参数(用户看不到参数名),重新定义路由规则

    MVC路由:由于路由global中注册了,在程序第一次运行时,在MVC会自动生成路由,类似于字典的格式缓存下来,但路由生成的规则又是怎样的呢? 路由生成规则是: 1>更具你定义的的顺序查找路由规 ...

  5. html的q标签、blockquote标签

    九层之台,起于垒土 一.<q> 定义和用法 <q> 标签定义短的引用.浏览器经常在引用的内容周围添加引号. <html> <body> <p> ...

  6. 20180308-Python内置方法

    先大致粗略的说一下反射的概念,不是很准确,后续详细讲解: 1. 以字符串的形式,导入模块 2. 以字符串的形式,获取模块内部的函数,并执行 通常我们想在一个模块中导入另外一个模块,则需要通过 impo ...

  7. Spring之控制反转——IoC、面向切面编程——AOP

      控制反转——IoC 提出IoC的目的 为了解决对象之间的耦合度过高的问题,提出了IoC理论,用来实现对象之间的解耦. 什么是IoC IoC是Inversion of Control的缩写,译为控制 ...

  8. 八、请求post、get、jsonp

    1.创建个 news 组件使用 2.在module.ts 引入模块 3.在使用的“Component”中不一样.这里是 http和jsonp 4.编写get请求查看效果 (1).编写好的get请求,点 ...

  9. MySQL系列之三查询优化

    通常来说,查询的生命周期大致可以按照顺序来看从客户端到服务端,然后在服务器上进行解析,生产执行计划, 执行,并返回结果给客户端.其中的执行阶段可以认为是整个生命周期中最重要的阶段,其中包括了大量为了检 ...

  10. vue中引入了sass,又引入cssnano报错

    "cssnano": { // preset: "advanced", autoprefixer: false, "postcss-zindex&qu ...